proxmox-rrd: add option to avoid page cache for load/save

use fadvice(.., POSIX_FADV_DONTNEED) for RRD files. We read those files only once,
and always rewrite them.

Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
Dietmar Maurer 2021-10-19 09:46:05 +02:00
parent 98eb435d90
commit 934c8724e2
3 changed files with 62 additions and 10 deletions

View File

@ -74,7 +74,7 @@ impl RRDMap {
if let Some(rrd) = self.map.get(rel_path) { if let Some(rrd) = self.map.get(rel_path) {
let mut path = self.config.basedir.clone(); let mut path = self.config.basedir.clone();
path.push(rel_path); path.push(rel_path);
rrd.save(&path, self.config.file_options.clone()) rrd.save(&path, self.config.file_options.clone(), true)
} else { } else {
bail!("rrd file {} not loaded", rel_path); bail!("rrd file {} not loaded", rel_path);
} }

View File

@ -12,11 +12,13 @@
//! * Arbitrary number of RRAs (dynamically changeable) //! * Arbitrary number of RRAs (dynamically changeable)
use std::path::Path; use std::path::Path;
use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use anyhow::{bail, format_err, Error}; use anyhow::{bail, format_err, Error};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use proxmox::tools::fs::{replace_file, CreateOptions}; use proxmox::tools::fs::{make_tmp_file, CreateOptions};
use proxmox_schema::api; use proxmox_schema::api;
use crate::rrd_v1; use crate::rrd_v1;
@ -321,8 +323,21 @@ impl RRD {
} }
/// Load data from a file /// Load data from a file
pub fn load(path: &Path) -> Result<Self, std::io::Error> { pub fn load(path: &Path, avoid_page_cache: bool) -> Result<Self, std::io::Error> {
let raw = std::fs::read(path)?;
let mut file = std::fs::File::open(path)?;
let buffer_size = file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0);
let mut raw = Vec::with_capacity(buffer_size);
file.read_to_end(&mut raw)?;
if avoid_page_cache {
nix::fcntl::posix_fadvise(
file.as_raw_fd(),
0,
buffer_size as i64,
nix::fcntl::PosixFadviseAdvice::POSIX_FADV_DONTNEED,
).map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err.to_string()))?;
}
match Self::from_raw(&raw) { match Self::from_raw(&raw) {
Ok(rrd) => Ok(rrd), Ok(rrd) => Ok(rrd),
@ -331,11 +346,48 @@ impl RRD {
} }
/// Store data into a file (atomic replace file) /// Store data into a file (atomic replace file)
pub fn save(&self, filename: &Path, options: CreateOptions) -> Result<(), Error> { pub fn save(
&self,
path: &Path,
options: CreateOptions,
avoid_page_cache: bool,
) -> Result<(), Error> {
let (fd, tmp_path) = make_tmp_file(&path, options)?;
let mut file = unsafe { std::fs::File::from_raw_fd(fd.into_raw_fd()) };
let mut try_block = || -> Result<(), Error> {
let mut data: Vec<u8> = Vec::new(); let mut data: Vec<u8> = Vec::new();
data.extend(&PROXMOX_RRD_MAGIC_2_0); data.extend(&PROXMOX_RRD_MAGIC_2_0);
serde_cbor::to_writer(&mut data, self)?; serde_cbor::to_writer(&mut data, self)?;
replace_file(filename, &data, options) file.write_all(&data)?;
if avoid_page_cache {
nix::fcntl::posix_fadvise(
file.as_raw_fd(),
0,
data.len() as i64,
nix::fcntl::PosixFadviseAdvice::POSIX_FADV_DONTNEED,
)?;
}
Ok(())
};
match try_block() {
Ok(()) => (),
error => {
let _ = nix::unistd::unlink(&tmp_path);
return error;
}
}
if let Err(err) = std::fs::rename(&tmp_path, &path) {
let _ = nix::unistd::unlink(&tmp_path);
bail!("Atomic rename failed - {}", err);
}
Ok(())
} }
pub fn last_update(&self) -> f64 { pub fn last_update(&self) -> f64 {

View File

@ -53,7 +53,7 @@ fn load_callback(
dst: DST, dst: DST,
) -> RRD { ) -> RRD {
match RRD::load(path) { match RRD::load(path, true) {
Ok(rrd) => rrd, Ok(rrd) => rrd,
Err(err) => { Err(err) => {
if err.kind() != std::io::ErrorKind::NotFound { if err.kind() != std::io::ErrorKind::NotFound {