Roll to a new segment: seal the current writer and create a new one.
(&mut self)
| 243 | |
| 244 | /// Roll to a new segment: seal the current writer and create a new one. |
| 245 | fn roll_segment(&mut self) -> Result<()> { |
| 246 | // Flush and seal the current segment. |
| 247 | self.writer.seal()?; |
| 248 | |
| 249 | // The new segment starts at the next LSN. |
| 250 | let new_first_lsn = self.writer.next_lsn(); |
| 251 | let new_path = segment_path(&self.wal_dir, new_first_lsn); |
| 252 | |
| 253 | let mut new_writer = |
| 254 | WalWriter::open_with_start_lsn(&new_path, self.writer_config.clone(), new_first_lsn)?; |
| 255 | |
| 256 | // Propagate encryption to the new writer with a fresh epoch. |
| 257 | // Each segment gets a new random epoch so the per-segment nonce space |
| 258 | // is independent. The ring's key material is preserved; only the epoch |
| 259 | // changes. The new preamble is written at the head of the new segment. |
| 260 | if let Some(ref ring) = self.encryption_ring { |
| 261 | let fresh_key = ring.current().with_fresh_epoch()?; |
| 262 | let new_ring = crate::crypto::KeyRing::new(fresh_key); |
| 263 | new_writer.set_encryption_ring(new_ring.clone())?; |
| 264 | self.encryption_ring = Some(new_ring); |
| 265 | } |
| 266 | |
| 267 | self.writer = new_writer; |
| 268 | self.active_first_lsn = new_first_lsn; |
| 269 | |
| 270 | // Fsync the WAL directory to ensure the new segment's directory |
| 271 | // entry is durable. Without this, a power loss could cause the |
| 272 | // new segment file to "disappear" on ext4/XFS. |
| 273 | let _ = crate::segment::fsync_directory(&self.wal_dir); |
| 274 | |
| 275 | info!( |
| 276 | segment = %new_path.display(), |
| 277 | first_lsn = new_first_lsn, |
| 278 | "rolled to new WAL segment" |
| 279 | ); |
| 280 | |
| 281 | Ok(()) |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | /// Replay all records from all segments in a WAL directory, in LSN order. |