use byteorder::{BigEndian, ReadBytesExt};
use bytes::{BufMut, BytesMut};
use noxu_util::lsn::Lsn;
use std::io::{self, Cursor};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum RollbackStartEntryError {
#[error("I/O error: {0}")]
Io(#[from] io::Error),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RollbackStartEntry {
pub active_txn_start: Lsn,
pub matchpoint_lsn: Lsn,
}
impl RollbackStartEntry {
pub fn new(active_txn_start: Lsn, matchpoint_lsn: Lsn) -> Self {
Self { active_txn_start, matchpoint_lsn }
}
pub fn log_size(&self) -> usize {
8 + 8 }
pub fn write_to_log(&self, buf: &mut BytesMut) {
buf.put_u64(self.active_txn_start.as_u64());
buf.put_u64(self.matchpoint_lsn.as_u64());
}
pub fn read_from_log(buf: &[u8]) -> Result<Self, RollbackStartEntryError> {
let mut cursor = Cursor::new(buf);
let active_txn_start = Lsn::from_u64(cursor.read_u64::<BigEndian>()?);
let matchpoint_lsn = Lsn::from_u64(cursor.read_u64::<BigEndian>()?);
Ok(Self { active_txn_start, matchpoint_lsn })
}
}
#[cfg(test)]
mod tests {
use super::*;
use noxu_util::lsn::{Lsn, NULL_LSN};
#[test]
fn test_rollback_start_roundtrip() {
let entry =
RollbackStartEntry::new(Lsn::new(3, 1200), Lsn::new(7, 4000));
let mut buf = BytesMut::new();
entry.write_to_log(&mut buf);
let decoded = RollbackStartEntry::read_from_log(&buf).unwrap();
assert_eq!(entry, decoded);
assert_eq!(decoded.active_txn_start, Lsn::new(3, 1200));
assert_eq!(decoded.matchpoint_lsn, Lsn::new(7, 4000));
}
#[test]
fn test_rollback_start_null_lsns() {
let entry = RollbackStartEntry::new(NULL_LSN, NULL_LSN);
let mut buf = BytesMut::new();
entry.write_to_log(&mut buf);
let decoded = RollbackStartEntry::read_from_log(&buf).unwrap();
assert_eq!(entry, decoded);
}
#[test]
fn test_log_size() {
let entry = RollbackStartEntry::new(NULL_LSN, NULL_LSN);
assert_eq!(entry.log_size(), 16);
assert_eq!(entry.log_size(), buf_size(&entry));
}
fn buf_size(entry: &RollbackStartEntry) -> usize {
let mut buf = BytesMut::new();
entry.write_to_log(&mut buf);
buf.len()
}
}