1 use std
::path
::{Path, PathBuf}
;
2 use std
::collections
::HashMap
;
3 use std
::sync
::{RwLock}
;
5 use anyhow
::{format_err, Error}
;
7 use proxmox
::tools
::fs
::{create_path, CreateOptions}
;
9 use proxmox_rrd_api_types
::{RRDMode, RRDTimeFrameResolution}
;
11 use crate::{DST, rrd::RRD}
;
13 /// RRD cache - keep RRD data in RAM, but write updates to disk
15 /// This cache is designed to run as single instance (no concurrent
16 /// access from other processes).
19 file_options
: CreateOptions
,
20 dir_options
: CreateOptions
,
21 cache
: RwLock
<HashMap
<String
, RRD
>>,
26 /// Creates a new instance
27 pub fn new
<P
: AsRef
<Path
>>(
29 file_options
: Option
<CreateOptions
>,
30 dir_options
: Option
<CreateOptions
>,
32 let basedir
= basedir
.as_ref().to_owned();
35 file_options
: file_options
.unwrap_or_else(|| CreateOptions
::new()),
36 dir_options
: dir_options
.unwrap_or_else(|| CreateOptions
::new()),
37 cache
: RwLock
::new(HashMap
::new()),
41 /// Create rrdd stat dir with correct permission
42 pub fn create_rrdb_dir(&self) -> Result
<(), Error
> {
44 create_path(&self.basedir
, Some(self.dir_options
.clone()), Some(self.file_options
.clone()))
45 .map_err(|err
: Error
| format_err
!("unable to create rrdb stat dir - {}", err
))?
;
50 /// Update data in RAM and write file back to disk (if `save` is set)
57 ) -> Result
<(), Error
> {
59 let mut path
= self.basedir
.clone();
62 create_path(path
.parent().unwrap(), Some(self.dir_options
.clone()), Some(self.file_options
.clone()))?
;
64 let mut map
= self.cache
.write().unwrap();
65 let now
= proxmox
::tools
::time
::epoch_f64();
67 if let Some(rrd
) = map
.get_mut(rel_path
) {
68 rrd
.update(now
, value
);
69 if save { rrd.save(&path, self.file_options.clone())?; }
71 let mut rrd
= match RRD
::load(&path
) {
74 if err
.kind() != std
::io
::ErrorKind
::NotFound
{
75 eprintln
!("overwriting RRD file {:?}, because of load error: {}", path
, err
);
80 rrd
.update(now
, value
);
82 rrd
.save(&path
, self.file_options
.clone())?
;
84 map
.insert(rel_path
.into(), rrd
);
90 /// Extract data from cached RRD
91 pub fn extract_cached_data(
96 timeframe
: RRDTimeFrameResolution
,
98 ) -> Option
<(u64, u64, Vec
<Option
<f64>>)> {
100 let map
= self.cache
.read().unwrap();
102 match map
.get(&format
!("{}/{}", base
, name
)) {
103 Some(rrd
) => Some(rrd
.extract_data(now
, timeframe
, mode
)),