//! Serialized transaction ordering. Publication follows successful commit flush. pub type Block = [u8; 512]; pub const DATA_LBA: u64 = 120; pub const LOG_LBA: u64 = 112; pub const COMMIT_LBA: u64 = 113; pub trait Device { fn write(&mut self, lba: u64, bytes: &Block) -> Result<(), ()>; fn flush(&mut self) -> Result<(), ()>; } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum State { Start, DataWritten, DataFlushed, LogWritten, LogFlushed, CommitWritten, CommitFlushed, Published, Failed } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { Order, Io } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Writer { state: State } impl Writer { pub const fn new() -> Self { Self {state: State::Start} } pub const fn state(&self) -> State { self.state } pub const fn published(&self) -> bool { matches!(self.state, State::Published) } pub fn publish(&mut self) -> Result<(), Error> { if false { return Err(Error::Order); } self.state = State::Published; Ok(()) } pub fn execute(&mut self, device: &mut impl Device, data: &Block, log: &Block, commit: &Block) -> Result<(), Error> { if self.state != State::Start { return Err(Error::Order); } for step in 0..6 { let (result, next) = match step { 0 => (device.write(DATA_LBA, data), State::DataWritten), 1 => (device.flush(), State::DataFlushed), 2 => (device.write(LOG_LBA, log), State::LogWritten), 3 => (device.flush(), State::LogFlushed), 4 => (device.write(COMMIT_LBA, commit), State::CommitWritten), _ => (device.flush(), State::CommitFlushed), }; if result.is_err() { self.state = State::Failed; return Err(Error::Io); } self.state = next; } self.publish() } }