Skip to content

Commit

Permalink
zcache/zcachedb: always flush stdout buffer data on termination (open…
Browse files Browse the repository at this point in the history
  • Loading branch information
sdimitro authored Feb 23, 2022
1 parent c59931c commit b435e9e
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 33 deletions.
2 changes: 1 addition & 1 deletion cmd/zfs_object_agent/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cmd/zfs_object_agent/util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum-map = { version = "1.1.1", features = ["serde"] }
lazy_static = "1.4.0"
log = "0.4"
log4rs = "1.0.0"
libc = "0.2"
more-asserts = "0.2.1"
num-traits = "0.2.14"
rand = "0.8.3"
Expand Down
49 changes: 25 additions & 24 deletions cmd/zfs_object_agent/util/src/write_stdout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,37 @@ to stdout/stderr returns an error (like `EPIPE`) rather than cause a panic.
These replacement macros also introduce buffering when stdout is not pointing to
tty, significantly improving the performance of utilities that redirect their
output to files.
DISCLAIMER: When the utility macros below are used to write to stdout it is
important to call flush_stdout!() before the program exits successfully to flush
any leftover data to non-tty endpoints (like pipes and regular files).
!*/

use lazy_static::lazy_static;
use libc::atexit;
use std::{io::BufWriter, sync::Mutex};

lazy_static! {
pub static ref BUFFERED_STDOUT_HANDLE: Mutex<BufWriter<std::io::Stdout>> =
Mutex::new(BufWriter::new(std::io::stdout()));
pub static ref BUFFERED_STDOUT_HANDLE: Mutex<BufWriter<std::io::Stdout>> = {
// Ensure that any leftover data in the buffer are flushed before
// terminating the process.
unsafe { atexit(flush_stdout) };
Mutex::new(BufWriter::new(std::io::stdout()))
};
}

extern "C" fn flush_stdout() {
use std::io::Write;
match BUFFERED_STDOUT_HANDLE.try_lock() {
Ok(mut hdl) => {
if let Err(e) = hdl.flush() {
crate::writeln_stderr!("{}", e);
std::process::exit(0);
}
}
Err(_) => {
crate::writeln_stderr!(
"CANNOT FLUSH STDOUT BUFFER BECAUSE ITS LOCK IS HELD BY ANOTHER THREAD"
);
std::process::exit(0);
}
};
}

pub extern crate atty;
Expand Down Expand Up @@ -63,24 +82,6 @@ macro_rules! writeln_stdout {
}}
}

/// Conventionally used at the end of main() so leftover buffer data are flushed
/// to stdout. The macro terminates the process on write errors (does not panic).
#[macro_export]
macro_rules! flush_stdout {
() => {{
use std::io::Write;
let res = if !$crate::write_stdout::atty::is($crate::write_stdout::atty::Stream::Stdout) {
let mut hdl = $crate::write_stdout::BUFFERED_STDOUT_HANDLE.lock().unwrap();
hdl.flush()
} else {
Ok(())
};
if res.is_err() {
std::process::exit(0)
}
}};
}

/// Similar to `eprint!` macro, except it terminates the process on write errors (does not panic).
#[macro_export]
macro_rules! write_stderr {
Expand Down
1 change: 0 additions & 1 deletion cmd/zfs_object_agent/zcache/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ chrono = "0.4"
async-trait = "0.1.51"
clap = "2"
exitcode = "1.1.2"
libc = "0.2"
log = "0.4"
more-asserts = "0.2.1"
num-traits = "0.2.14"
Expand Down
2 changes: 0 additions & 2 deletions cmd/zfs_object_agent/zcache/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use log::*;
use report_hits::ReportHits;
use stats::Stats;
use subcommand::ZcacheSubCommand;
use util::flush_stdout;
use util::writeln_stderr;

fn main() -> Result<()> {
Expand Down Expand Up @@ -96,6 +95,5 @@ async fn async_main() -> Result<()> {
std::process::exit(exitcode::USAGE);
}
}
flush_stdout!();
Ok(())
}
7 changes: 2 additions & 5 deletions cmd/zfs_object_agent/zcdb/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use clap::AppSettings;
use clap::Arg;
use clap::SubCommand;
use git_version::git_version;
use util::flush_stdout;
use util::writeln_stdout;
use zettacache::DumpSlabsOptions;
use zettacache::DumpStructuresOptions;
Expand Down Expand Up @@ -95,7 +94,7 @@ async fn main() -> Result<(), anyhow::Error> {
.get_matches();

let cache_paths = matches.values_of("cache-device").unwrap().collect();
let res = match matches.subcommand() {
match matches.subcommand() {
("dump-structures", Some(subcommand_matches)) => {
ZettaCacheDBCommand::issue_command(
ZettaCacheDBCommand::DumpStructures(
Expand Down Expand Up @@ -135,7 +134,5 @@ async fn main() -> Result<(), anyhow::Error> {
writeln_stdout!("{}", matches.usage());
std::process::exit(exitcode::USAGE);
}
};
flush_stdout!();
res
}
}

0 comments on commit b435e9e

Please sign in to comment.