nodedb_wal/writer/
config.rs1use std::path::{Path, PathBuf};
4use std::sync::Arc;
5
6use crate::align::DEFAULT_ALIGNMENT;
7use crate::double_write::{DoubleWriteBuffer, DwbDegradation, DwbMode, DwbProtection};
8use crate::time_anchors::TimeAnchors;
9
10pub const DEFAULT_WRITE_BUFFER_SIZE: usize = 2 * 1024 * 1024;
18
19#[derive(Debug, Clone)]
21pub struct WalWriterConfig {
22 pub write_buffer_size: usize,
24
25 pub alignment: usize,
27
28 pub use_direct_io: bool,
31
32 pub dwb_mode: Option<DwbMode>,
36
37 pub time_anchors: Option<Arc<TimeAnchors>>,
41}
42
43impl Default for WalWriterConfig {
44 fn default() -> Self {
45 Self {
46 write_buffer_size: DEFAULT_WRITE_BUFFER_SIZE,
47 alignment: DEFAULT_ALIGNMENT,
48 use_direct_io: true,
49 dwb_mode: None,
50 time_anchors: None,
51 }
52 }
53}
54
55pub(crate) fn resolve_dwb_mode(config: &WalWriterConfig) -> DwbMode {
56 config
57 .dwb_mode
58 .unwrap_or_else(|| DwbMode::default_for_parent(config.use_direct_io))
59}
60
61pub(crate) struct DwbSetup {
66 pub path: Option<PathBuf>,
69 pub buffer: Option<DoubleWriteBuffer>,
70 pub protection: DwbProtection,
71}
72
73pub(crate) fn open_dwb_for(config: &WalWriterConfig, path: &Path) -> DwbSetup {
74 let mode = resolve_dwb_mode(config);
75 if mode == DwbMode::Off {
76 return DwbSetup {
77 path: None,
78 buffer: None,
79 protection: DwbProtection::Off,
80 };
81 }
82 let dwb_path = path.with_extension("dwb");
83 let (buffer, protection) = match open_dwb_at(&dwb_path, mode) {
84 Some(d) => (Some(d), DwbProtection::Active),
85 None => (None, DwbProtection::Degraded(DwbDegradation::OpenFailed)),
86 };
87 DwbSetup {
88 path: Some(dwb_path),
89 buffer,
90 protection,
91 }
92}
93
94pub(crate) fn open_dwb_at(dwb_path: &Path, mode: DwbMode) -> Option<DoubleWriteBuffer> {
97 match DoubleWriteBuffer::open(dwb_path, mode) {
98 Ok(dwb) => Some(dwb),
99 Err(e) => {
100 tracing::warn!(
101 path = %dwb_path.display(),
102 error = %e,
103 mode = ?mode,
104 "failed to open DWB — torn-write protection lost for this writer"
105 );
106 None
107 }
108 }
109}
110
111pub fn resume_offset(end_offset: u64, use_direct_io: bool, alignment: usize, path: &Path) -> u64 {
119 if !use_direct_io {
120 return end_offset;
121 }
122 let alignment = alignment as u64;
123 let aligned = end_offset - (end_offset % alignment);
124 if aligned != end_offset {
125 tracing::warn!(
126 path = %path.display(),
127 end_offset,
128 resume_offset = aligned,
129 "WAL segment ends mid-block — discarding the torn final block (never fsynced, never acknowledged)"
130 );
131 }
132 aligned
133}