proxmox-rrd: log journal apply/flush times, split apply and flush

We need to apply the journal only once.
This commit is contained in:
Dietmar Maurer 2021-10-14 16:41:08 +02:00
parent 7484fce24d
commit 658357c5a8
1 changed files with 58 additions and 18 deletions

View File

@ -5,6 +5,7 @@ use std::sync::RwLock;
use std::io::Write; use std::io::Write;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::time::SystemTime;
use anyhow::{format_err, bail, Error}; use anyhow::{format_err, bail, Error};
use nix::fcntl::OFlag; use nix::fcntl::OFlag;
@ -33,6 +34,7 @@ struct RRDCacheState {
rrd_map: HashMap<String, RRD>, rrd_map: HashMap<String, RRD>,
journal: File, journal: File,
last_journal_flush: f64, last_journal_flush: f64,
journal_applied: bool,
} }
struct JournalEntry { struct JournalEntry {
@ -83,6 +85,7 @@ impl RRDCache {
journal, journal,
rrd_map: HashMap::new(), rrd_map: HashMap::new(),
last_journal_flush: 0.0, last_journal_flush: 0.0,
journal_applied: false,
}; };
Ok(Self { Ok(Self {
@ -171,18 +174,46 @@ impl RRDCache {
Ok(()) Ok(())
} }
/// Apply journal. Should be used at server startup. /// Apply and commit the journal. Should be used at server startup.
pub fn apply_journal(&self) -> Result<(), Error> { pub fn apply_journal(&self) -> Result<(), Error> {
let mut state = self.state.write().unwrap(); // block writers let mut state = self.state.write().unwrap(); // block writers
self.apply_journal_locked(&mut state) self.apply_and_commit_journal_locked(&mut state)
} }
fn apply_journal_locked(&self, state: &mut RRDCacheState) -> Result<(), Error> { fn apply_and_commit_journal_locked(&self, state: &mut RRDCacheState) -> Result<(), Error> {
log::info!("applying rrd journal");
state.last_journal_flush = proxmox_time::epoch_f64(); state.last_journal_flush = proxmox_time::epoch_f64();
if !state.journal_applied {
let start_time = SystemTime::now();
log::debug!("applying rrd journal");
match self.apply_journal_locked(state) {
Ok(entries) => {
let elapsed = start_time.elapsed()?.as_secs_f64();
log::info!("applied rrd journal ({} entries in {:.3} seconds)", entries, elapsed);
}
Err(err) => bail!("apply rrd journal failed - {}", err),
}
}
let start_time = SystemTime::now();
log::debug!("commit rrd journal");
match self.commit_journal_locked(state) {
Ok(rrd_file_count) => {
let elapsed = start_time.elapsed()?.as_secs_f64();
log::info!("rrd journal successfully committed ({} files in {:.3} seconds)",
rrd_file_count, elapsed);
}
Err(err) => bail!("rrd journal commit failed: {}", err),
}
Ok(())
}
fn apply_journal_locked(&self, state: &mut RRDCacheState) -> Result<usize, Error> {
let mut journal_path = self.basedir.clone(); let mut journal_path = self.basedir.clone();
journal_path.push(RRD_JOURNAL_NAME); journal_path.push(RRD_JOURNAL_NAME);
@ -234,10 +265,22 @@ impl RRDCache {
} }
} }
// We need to apply the journal only once, because further updates
// are always directly applied.
state.journal_applied = true;
Ok(linenr)
}
fn commit_journal_locked(&self, state: &mut RRDCacheState) -> Result<usize, Error> {
// save all RRDs // save all RRDs
let mut rrd_file_count = 0;
let mut errors = 0; let mut errors = 0;
for (rel_path, rrd) in state.rrd_map.iter() { for (rel_path, rrd) in state.rrd_map.iter() {
rrd_file_count += 1;
let mut path = self.basedir.clone(); let mut path = self.basedir.clone();
path.push(&rel_path); path.push(&rel_path);
if let Err(err) = rrd.save(&path, self.file_options.clone()) { if let Err(err) = rrd.save(&path, self.file_options.clone()) {
@ -246,17 +289,16 @@ impl RRDCache {
} }
} }
// if everything went ok, commit the journal if errors != 0 {
bail!("errors during rrd flush - unable to commit rrd journal");
if errors == 0 {
nix::unistd::ftruncate(state.journal.as_raw_fd(), 0)
.map_err(|err| format_err!("unable to truncate journal - {}", err))?;
log::info!("rrd journal successfully committed");
} else {
log::error!("errors during rrd flush - unable to commit rrd journal");
} }
Ok(()) // if everything went ok, commit the journal
nix::unistd::ftruncate(state.journal.as_raw_fd(), 0)
.map_err(|err| format_err!("unable to truncate journal - {}", err))?;
Ok(rrd_file_count)
} }
/// Update data in RAM and write file back to disk (journal) /// Update data in RAM and write file back to disk (journal)
@ -270,10 +312,8 @@ impl RRDCache {
let mut state = self.state.write().unwrap(); // block other writers let mut state = self.state.write().unwrap(); // block other writers
if (time - state.last_journal_flush) > self.apply_interval { if !state.journal_applied || (time - state.last_journal_flush) > self.apply_interval {
if let Err(err) = self.apply_journal_locked(&mut state) { self.apply_and_commit_journal_locked(&mut state)?;
log::error!("apply journal failed: {}", err);
}
} }
Self::append_journal_entry(&mut state, time, value, dst, rel_path)?; Self::append_journal_entry(&mut state, time, value, dst, rel_path)?;