rrd: try to load database if not already present in cache

Before, a call to `update` was necessary to load an existing database
into the cache. If `update` was never called, `extract_cached_data`
would simply return no data.

Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
This commit is contained in:
Lukas Wagner 2024-08-06 14:59:53 +02:00 committed by Wolfgang Bumiller
parent f01c1e0ce9
commit 7ea63a6fb9
2 changed files with 55 additions and 15 deletions

View File

@ -12,7 +12,7 @@ use crossbeam_channel::{bounded, TryRecvError};
use proxmox_sys::fs::{create_path, CreateOptions}; use proxmox_sys::fs::{create_path, CreateOptions};
use crate::rrd::{AggregationFn, Archive, DataSourceType, Database}; use crate::rrd::{AggregationFn, DataSourceType, Database};
use crate::Entry; use crate::Entry;
mod journal; mod journal;
@ -58,7 +58,8 @@ impl Cache {
file_options: Option<CreateOptions>, file_options: Option<CreateOptions>,
dir_options: Option<CreateOptions>, dir_options: Option<CreateOptions>,
apply_interval: f64, apply_interval: f64,
load_rrd_cb: fn(path: &Path, rel_path: &str, dst: DataSourceType) -> Database, load_rrd_cb: fn(path: &Path, rel_path: &str) -> Option<Database>,
create_rrd_cb: fn(dst: DataSourceType) -> Database,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let basedir = basedir.as_ref().to_owned(); let basedir = basedir.as_ref().to_owned();
@ -80,7 +81,7 @@ impl Cache {
}); });
let state = JournalState::new(Arc::clone(&config))?; let state = JournalState::new(Arc::clone(&config))?;
let rrd_map = RRDMap::new(Arc::clone(&config), load_rrd_cb); let rrd_map = RRDMap::new(Arc::clone(&config), load_rrd_cb, create_rrd_cb);
Ok(Self { Ok(Self {
config: Arc::clone(&config), config: Arc::clone(&config),
@ -248,10 +249,24 @@ impl Cache {
start: Option<u64>, start: Option<u64>,
end: Option<u64>, end: Option<u64>,
) -> Result<Option<Entry>, Error> { ) -> Result<Option<Entry>, Error> {
self.rrd_map let res = {
.read() let map = self.rrd_map.read().unwrap();
.unwrap() map.extract_cached_data(base, name, cf, resolution, start, end)?
.extract_cached_data(base, name, cf, resolution, start, end) };
match res {
Some(entry) => Ok(Some(entry)),
None => {
let mut map = self.rrd_map.write().unwrap();
let loaded = map.load(&format!("{base}/{name}"))?;
if loaded {
map.extract_cached_data(base, name, cf, resolution, start, end)
} else {
Ok(None)
}
}
}
} }
} }

View File

@ -14,18 +14,21 @@ use crate::Entry;
pub struct RRDMap { pub struct RRDMap {
config: Arc<CacheConfig>, config: Arc<CacheConfig>,
map: HashMap<String, Database>, map: HashMap<String, Database>,
load_rrd_cb: fn(path: &Path, rel_path: &str, dst: DataSourceType) -> Database, load_rrd_cb: fn(path: &Path, rel_path: &str) -> Option<Database>,
create_rrd_cb: fn(dst: DataSourceType) -> Database,
} }
impl RRDMap { impl RRDMap {
pub(crate) fn new( pub(crate) fn new(
config: Arc<CacheConfig>, config: Arc<CacheConfig>,
load_rrd_cb: fn(path: &Path, rel_path: &str, dst: DataSourceType) -> Database, load_rrd_cb: fn(path: &Path, rel_path: &str) -> Option<Database>,
create_rrd_cb: fn(dst: DataSourceType) -> Database,
) -> Self { ) -> Self {
Self { Self {
config, config,
map: HashMap::new(), map: HashMap::new(),
load_rrd_cb, load_rrd_cb,
create_rrd_cb,
} }
} }
@ -44,13 +47,18 @@ impl RRDMap {
} else { } else {
let mut path = self.config.basedir.clone(); let mut path = self.config.basedir.clone();
path.push(rel_path); path.push(rel_path);
create_path( let mut rrd = match (self.load_rrd_cb)(&path, rel_path) {
path.parent().unwrap(), None => {
Some(self.config.dir_options.clone()), create_path(
Some(self.config.dir_options.clone()), path.parent().unwrap(),
)?; Some(self.config.dir_options.clone()),
Some(self.config.dir_options.clone()),
)?;
let mut rrd = (self.load_rrd_cb)(&path, rel_path, dst); (self.create_rrd_cb)(dst)
}
Some(rrd) => rrd,
};
if !new_only || time > rrd.last_update() { if !new_only || time > rrd.last_update() {
rrd.update(time, value); rrd.update(time, value);
@ -94,4 +102,21 @@ impl RRDMap {
None => Ok(None), None => Ok(None),
} }
} }
pub fn load(&mut self, rel_path: &str) -> Result<bool, Error> {
if self.map.get(rel_path).is_some() {
// Already loaded, do nothing
return Ok(true);
}
let mut path = self.config.basedir.clone();
path.push(rel_path);
if let Some(rrd) = (self.load_rrd_cb)(&path, rel_path) {
self.map.insert(rel_path.to_string(), rrd);
return Ok(true);
} else {
return Ok(false);
}
}
} }