use std::path::{Path, PathBuf};
use std::sync::Arc;
use crate::align::DEFAULT_ALIGNMENT;
use crate::double_write::{DoubleWriteBuffer, DwbDegradation, DwbMode, DwbProtection};
use crate::time_anchors::TimeAnchors;
pub const DEFAULT_WRITE_BUFFER_SIZE: usize = 2 * 1024 * 1024;
#[derive(Debug, Clone)]
pub struct WalWriterConfig {
pub write_buffer_size: usize,
pub alignment: usize,
pub use_direct_io: bool,
pub dwb_mode: Option<DwbMode>,
pub time_anchors: Option<Arc<TimeAnchors>>,
}
impl Default for WalWriterConfig {
fn default() -> Self {
Self {
write_buffer_size: DEFAULT_WRITE_BUFFER_SIZE,
alignment: DEFAULT_ALIGNMENT,
use_direct_io: true,
dwb_mode: None,
time_anchors: None,
}
}
}
pub(crate) fn resolve_dwb_mode(config: &WalWriterConfig) -> DwbMode {
config
.dwb_mode
.unwrap_or_else(|| DwbMode::default_for_parent(config.use_direct_io))
}
pub(crate) struct DwbSetup {
pub path: Option<PathBuf>,
pub buffer: Option<DoubleWriteBuffer>,
pub protection: DwbProtection,
}
pub(crate) fn open_dwb_for(config: &WalWriterConfig, path: &Path) -> DwbSetup {
let mode = resolve_dwb_mode(config);
if mode == DwbMode::Off {
return DwbSetup {
path: None,
buffer: None,
protection: DwbProtection::Off,
};
}
let dwb_path = path.with_extension("dwb");
let (buffer, protection) = match open_dwb_at(&dwb_path, mode) {
Some(d) => (Some(d), DwbProtection::Active),
None => (None, DwbProtection::Degraded(DwbDegradation::OpenFailed)),
};
DwbSetup {
path: Some(dwb_path),
buffer,
protection,
}
}
pub(crate) fn open_dwb_at(dwb_path: &Path, mode: DwbMode) -> Option<DoubleWriteBuffer> {
match DoubleWriteBuffer::open(dwb_path, mode) {
Ok(dwb) => Some(dwb),
Err(e) => {
tracing::warn!(
path = %dwb_path.display(),
error = %e,
mode = ?mode,
"failed to open DWB — torn-write protection lost for this writer"
);
None
}
}
}
pub fn resume_offset(end_offset: u64, use_direct_io: bool, alignment: usize, path: &Path) -> u64 {
if !use_direct_io {
return end_offset;
}
let alignment = alignment as u64;
let aligned = end_offset - (end_offset % alignment);
if aligned != end_offset {
tracing::warn!(
path = %path.display(),
end_offset,
resume_offset = aligned,
"WAL segment ends mid-block — discarding the torn final block (never fsynced, never acknowledged)"
);
}
aligned
}