use std::os::unix::io::AsRawFd;
use crate::error::{Result, WalError};
use super::core::WalWriter;
impl WalWriter {
pub(super) fn flush_buffer(&mut self) -> Result<()> {
if self.buffer.is_empty() {
return Ok(());
}
nodedb_types::fail_point_err!("wal::flush_out_of_space", |_: String| {
const SITE: &str = "WAL segment append (failpoint)";
let err = WalError::OutOfSpace { context: SITE };
crate::diag::out_of_space(&err, SITE, self.file_offset, self.buffer.len() as u64);
err
});
let data = if self.config.use_direct_io {
crate::record::pad_buffer_to_alignment(
&mut self.buffer,
self.config.alignment,
"write buffer has no room for its alignment padding record",
)?;
self.buffer.as_aligned_slice()
} else {
self.buffer.as_slice()
};
let fd = self.file.as_raw_fd();
let mut remaining = data;
let mut write_offset = self.file_offset;
while !remaining.is_empty() {
let written = unsafe {
libc::pwrite(
fd,
remaining.as_ptr() as *const libc::c_void,
remaining.len(),
write_offset as libc::off_t,
)
};
if written < 0 {
return Err(write_error(
"WAL segment append",
write_offset,
remaining.len() as u64,
));
}
let n = written as usize;
if n == 0 {
return Err(WalError::Io(std::io::Error::new(
std::io::ErrorKind::WriteZero,
"WAL pwrite made no progress",
)));
}
remaining = &remaining[n..];
write_offset += n as u64;
}
self.file_offset += data.len() as u64;
self.buffer.clear();
self.durability.record_flush();
Ok(())
}
}
fn write_error(context: &'static str, offset: u64, pending: u64) -> WalError {
let err = std::io::Error::last_os_error();
if err.raw_os_error() == Some(libc::ENOSPC) {
let out_of_space = WalError::OutOfSpace { context };
crate::diag::out_of_space(&out_of_space, context, offset, pending);
return out_of_space;
}
WalError::Io(err)
}