]>
Commit | Line | Data |
---|---|---|
192ece47 DM |
1 | //! Round Robin Database cache |
2 | //! | |
3 | //! RRD files are stored under `/var/lib/proxmox-backup/rrdb/`. Only a | |
4 | //! single process may access and update those files, so we initialize | |
5 | //! and update RRD data inside `proxmox-backup-proxy`. | |
6 | ||
2e3f94e1 DM |
7 | use std::path::Path; |
8 | ||
fae4f6c5 DM |
9 | use anyhow::{format_err, Error}; |
10 | use once_cell::sync::OnceCell; | |
11 | ||
f0c26122 LW |
12 | use proxmox_rrd::rrd::{AggregationFn, DataSourceType, Database}; |
13 | use proxmox_rrd::Cache; | |
9531d2c5 | 14 | use proxmox_sys::fs::CreateOptions; |
fae4f6c5 DM |
15 | |
16 | use pbs_api_types::{RRDMode, RRDTimeFrame}; | |
9531d2c5 | 17 | use pbs_buildcfg::PROXMOX_BACKUP_STATE_DIR_M; |
fae4f6c5 | 18 | |
b9352095 DM |
19 | const RRD_CACHE_BASEDIR: &str = concat!(PROXMOX_BACKUP_STATE_DIR_M!(), "/rrdb"); |
20 | ||
f0c26122 | 21 | static RRD_CACHE: OnceCell<Cache> = OnceCell::new(); |
fae4f6c5 DM |
22 | |
23 | /// Get the RRD cache instance | |
f0c26122 | 24 | pub fn get_rrd_cache() -> Result<&'static Cache, Error> { |
9531d2c5 TL |
25 | RRD_CACHE |
26 | .get() | |
27 | .ok_or_else(|| format_err!("RRD cache not initialized!")) | |
fae4f6c5 DM |
28 | } |
29 | ||
30 | /// Initialize the RRD cache instance | |
31 | /// | |
32 | /// Note: Only a single process must do this (proxmox-backup-proxy) | |
f0c26122 | 33 | pub fn initialize_rrd_cache() -> Result<&'static Cache, Error> { |
fae4f6c5 DM |
34 | let backup_user = pbs_config::backup_user()?; |
35 | ||
36 | let file_options = CreateOptions::new() | |
37 | .owner(backup_user.uid) | |
38 | .group(backup_user.gid); | |
39 | ||
40 | let dir_options = CreateOptions::new() | |
41 | .owner(backup_user.uid) | |
42 | .group(backup_user.gid); | |
43 | ||
9531d2c5 | 44 | let apply_interval = 30.0 * 60.0; // 30 minutes |
fae4f6c5 | 45 | |
f0c26122 | 46 | let cache = Cache::new( |
b9352095 | 47 | RRD_CACHE_BASEDIR, |
fae4f6c5 DM |
48 | Some(file_options), |
49 | Some(dir_options), | |
50 | apply_interval, | |
2e3f94e1 | 51 | load_callback, |
fae4f6c5 DM |
52 | )?; |
53 | ||
9531d2c5 TL |
54 | RRD_CACHE |
55 | .set(cache) | |
fae4f6c5 DM |
56 | .map_err(|_| format_err!("RRD cache already initialized!"))?; |
57 | ||
58 | Ok(RRD_CACHE.get().unwrap()) | |
59 | } | |
60 | ||
f0c26122 LW |
61 | fn load_callback(path: &Path, _rel_path: &str, dst: DataSourceType) -> Database { |
62 | match Database::load(path, true) { | |
2e3f94e1 DM |
63 | Ok(rrd) => rrd, |
64 | Err(err) => { | |
65 | if err.kind() != std::io::ErrorKind::NotFound { | |
9531d2c5 TL |
66 | log::warn!( |
67 | "overwriting RRD file {:?}, because of load error: {}", | |
68 | path, | |
69 | err | |
70 | ); | |
2e3f94e1 | 71 | } |
f0c26122 | 72 | Cache::create_proxmox_backup_default_rrd(dst) |
9531d2c5 | 73 | } |
2e3f94e1 DM |
74 | } |
75 | } | |
76 | ||
fae4f6c5 DM |
77 | /// Extracts data for the specified time frame from from RRD cache |
78 | pub fn extract_rrd_data( | |
79 | basedir: &str, | |
80 | name: &str, | |
81 | timeframe: RRDTimeFrame, | |
82 | mode: RRDMode, | |
92ead5d3 | 83 | ) -> Result<Option<proxmox_rrd::Entry>, Error> { |
fae4f6c5 DM |
84 | let end = proxmox_time::epoch_f64() as u64; |
85 | ||
86 | let (start, resolution) = match timeframe { | |
87 | RRDTimeFrame::Hour => (end - 3600, 60), | |
9531d2c5 TL |
88 | RRDTimeFrame::Day => (end - 3600 * 24, 60), |
89 | RRDTimeFrame::Week => (end - 3600 * 24 * 7, 30 * 60), | |
90 | RRDTimeFrame::Month => (end - 3600 * 24 * 30, 30 * 60), | |
91 | RRDTimeFrame::Year => (end - 3600 * 24 * 365, 6 * 60 * 60), | |
92 | RRDTimeFrame::Decade => (end - 10 * 3600 * 24 * 366, 7 * 86400), | |
fae4f6c5 DM |
93 | }; |
94 | ||
95 | let cf = match mode { | |
f0c26122 LW |
96 | RRDMode::Max => AggregationFn::Maximum, |
97 | RRDMode::Average => AggregationFn::Average, | |
fae4f6c5 DM |
98 | }; |
99 | ||
100 | let rrd_cache = get_rrd_cache()?; | |
101 | ||
102 | rrd_cache.extract_cached_data(basedir, name, cf, resolution, Some(start), Some(end)) | |
103 | } | |
104 | ||
98eb435d DM |
105 | /// Sync/Flush the RRD journal |
106 | pub fn rrd_sync_journal() { | |
107 | if let Ok(rrd_cache) = get_rrd_cache() { | |
108 | if let Err(err) = rrd_cache.sync_journal() { | |
109 | log::error!("rrd_sync_journal failed - {}", err); | |
110 | } | |
111 | } | |
112 | } | |
fae4f6c5 DM |
113 | /// Update RRD Gauge values |
114 | pub fn rrd_update_gauge(name: &str, value: f64) { | |
115 | if let Ok(rrd_cache) = get_rrd_cache() { | |
58f70bcc | 116 | let now = proxmox_time::epoch_f64(); |
f0c26122 | 117 | if let Err(err) = rrd_cache.update_value(name, now, value, DataSourceType::Gauge) { |
fae4f6c5 DM |
118 | log::error!("rrd::update_value '{}' failed - {}", name, err); |
119 | } | |
120 | } | |
121 | } | |
122 | ||
123 | /// Update RRD Derive values | |
124 | pub fn rrd_update_derive(name: &str, value: f64) { | |
125 | if let Ok(rrd_cache) = get_rrd_cache() { | |
58f70bcc | 126 | let now = proxmox_time::epoch_f64(); |
f0c26122 | 127 | if let Err(err) = rrd_cache.update_value(name, now, value, DataSourceType::Derive) { |
fae4f6c5 DM |
128 | log::error!("rrd::update_value '{}' failed - {}", name, err); |
129 | } | |
130 | } | |
131 | } |