From: Matt Corallo Date: Sun, 3 Apr 2022 01:04:26 +0000 (+0000) Subject: Pipe filesystem writes in `lightning-persister` through `BufWriter` X-Git-Tag: v0.0.107~62^2 X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=refs%2Fheads%2F2022-04-buf-writes;p=rust-lightning Pipe filesystem writes in `lightning-persister` through `BufWriter` We generally make no effort to ensure all writes are buffered in lower-level objects, so wrapping write calls in `BufWriter` may substantially improve performance in some cases. This is especially important now that we block the sample node exit until the `NetworkGraph` has been written out, which includes many small-ish writes. With this change, shutdown of the sample node on a relatively underpowered device went from 15-30 seconds of CPU time to a second or two, plus IO sync time. --- diff --git a/lightning-persister/src/lib.rs b/lightning-persister/src/lib.rs index da64cb375..450062127 100644 --- a/lightning-persister/src/lib.rs +++ b/lightning-persister/src/lib.rs @@ -28,7 +28,7 @@ use lightning::ln::channelmanager::ChannelManager; use lightning::util::logger::Logger; use lightning::util::ser::{ReadableArgs, Writeable}; use std::fs; -use std::io::{Cursor, Error}; +use std::io::{Cursor, Error, Write}; use std::ops::Deref; use std::path::{Path, PathBuf}; @@ -49,7 +49,7 @@ pub struct FilesystemPersister { } impl DiskWriteable for ChannelMonitor { - fn write_to_file(&self, writer: &mut fs::File) -> Result<(), Error> { + fn write_to_file(&self, writer: &mut W) -> Result<(), Error> { self.write(writer) } } @@ -62,13 +62,13 @@ where F::Target: FeeEstimator, L::Target: Logger, { - fn write_to_file(&self, writer: &mut fs::File) -> Result<(), std::io::Error> { + fn write_to_file(&self, writer: &mut W) -> Result<(), std::io::Error> { self.write(writer) } } impl DiskWriteable for NetworkGraph { - fn write_to_file(&self, writer: &mut fs::File) -> Result<(), std::io::Error> { + fn write_to_file(&self, writer: &mut W) -> Result<(), std::io::Error> { self.write(writer) } } diff --git a/lightning-persister/src/util.rs b/lightning-persister/src/util.rs index 73b28985b..f26296794 100644 --- a/lightning-persister/src/util.rs +++ b/lightning-persister/src/util.rs @@ -3,6 +3,7 @@ extern crate winapi; use std::fs; use std::path::{Path, PathBuf}; +use std::io::{BufWriter, Write}; #[cfg(not(target_os = "windows"))] use std::os::unix::io::AsRawFd; @@ -14,7 +15,7 @@ use { }; pub(crate) trait DiskWriteable { - fn write_to_file(&self, writer: &mut fs::File) -> Result<(), std::io::Error>; + fn write_to_file(&self, writer: &mut W) -> Result<(), std::io::Error>; } pub(crate) fn get_full_filepath(mut filepath: PathBuf, filename: String) -> String { @@ -52,9 +53,9 @@ pub(crate) fn write_to_file(path: PathBuf, filename: String, d { // Note that going by rust-lang/rust@d602a6b, on MacOS it is only safe to use // rust stdlib 1.36 or higher. - let mut f = fs::File::create(&tmp_filename)?; - data.write_to_file(&mut f)?; - f.sync_all()?; + let mut buf = BufWriter::new(fs::File::create(&tmp_filename)?); + data.write_to_file(&mut buf)?; + buf.into_inner()?.sync_all()?; } // Fsync the parent directory on Unix. #[cfg(not(target_os = "windows"))] @@ -95,7 +96,7 @@ mod tests { struct TestWriteable{} impl DiskWriteable for TestWriteable { - fn write_to_file(&self, writer: &mut fs::File) -> Result<(), io::Error> { + fn write_to_file(&self, writer: &mut W) -> Result<(), io::Error> { writer.write_all(&[42; 1]) } } @@ -145,7 +146,7 @@ mod tests { fn test_diskwriteable_failure() { struct FailingWriteable {} impl DiskWriteable for FailingWriteable { - fn write_to_file(&self, _writer: &mut fs::File) -> Result<(), std::io::Error> { + fn write_to_file(&self, _writer: &mut W) -> Result<(), std::io::Error> { Err(std::io::Error::new(std::io::ErrorKind::Other, "expected failure")) } }