use crate::entry_states::SlotState;
use noxu_util::Lsn;
#[derive(Debug, Clone)]
pub struct DeltaInfo {
pub key: Vec<u8>,
pub lsn: Lsn,
pub state: SlotState,
}
impl DeltaInfo {
pub fn new(key: Vec<u8>, lsn: Lsn, state: SlotState) -> Self {
DeltaInfo { key, lsn, state }
}
#[inline]
pub fn is_known_deleted(&self) -> bool {
self.state.is_known_deleted()
}
#[inline]
pub fn is_pending_deleted(&self) -> bool {
self.state.is_pending_deleted()
}
#[inline]
pub fn is_dirty(&self) -> bool {
self.state.is_dirty()
}
#[inline]
pub fn is_embedded_ln(&self) -> bool {
self.state.is_embedded_ln()
}
pub fn log_size(&self) -> usize {
2 + self.key.len() + 8 + 1 }
pub fn write_to_log(&self, buffer: &mut Vec<u8>) {
let key_len = self.key.len() as u16;
buffer.extend_from_slice(&key_len.to_le_bytes());
buffer.extend_from_slice(&self.key);
buffer.extend_from_slice(&self.lsn.as_u64().to_le_bytes());
buffer.push(self.state.as_byte());
}
pub fn read_from_log(data: &[u8]) -> Result<(Self, usize), String> {
let mut offset = 0;
if data.len() < 2 {
return Err("Not enough data for key length".to_string());
}
let key_len = u16::from_le_bytes([data[0], data[1]]) as usize;
offset += 2;
if data.len() < offset + key_len {
return Err("Not enough data for key".to_string());
}
let key = data[offset..offset + key_len].to_vec();
offset += key_len;
if data.len() < offset + 8 {
return Err("Not enough data for LSN".to_string());
}
let lsn_bytes: [u8; 8] = data[offset..offset + 8]
.try_into()
.map_err(|_| "Failed to read LSN bytes")?;
let lsn = Lsn::from_u64(u64::from_le_bytes(lsn_bytes));
offset += 8;
if data.len() < offset + 1 {
return Err("Not enough data for state".to_string());
}
let state = SlotState::from_byte(data[offset]);
offset += 1;
Ok((DeltaInfo::new(key, lsn, state), offset))
}
}
#[cfg(test)]
mod tests {
use super::*;
use noxu_util::{Lsn, NULL_LSN};
#[test]
fn test_new() {
let key = b"test_key".to_vec();
let lsn = Lsn::new(1, 1000);
let state = SlotState::new();
let delta = DeltaInfo::new(key.clone(), lsn, state);
assert_eq!(delta.key, key);
assert_eq!(delta.lsn, lsn);
assert!(!delta.is_dirty());
}
#[test]
fn test_state_flags() {
let key = b"key".to_vec();
let lsn = Lsn::new(5, 5000);
let mut state = SlotState::new();
state.set_dirty();
state.set_embedded_ln();
let delta = DeltaInfo::new(key, lsn, state);
assert!(delta.is_dirty());
assert!(delta.is_embedded_ln());
assert!(!delta.is_known_deleted());
assert!(!delta.is_pending_deleted());
}
#[test]
fn test_log_size() {
let key = b"test".to_vec();
let lsn = NULL_LSN;
let state = SlotState::new();
let delta = DeltaInfo::new(key, lsn, state);
assert_eq!(delta.log_size(), 15);
}
#[test]
fn test_log_size_empty_key() {
let key = Vec::new();
let lsn = Lsn::new(1, 1);
let state = SlotState::new();
let delta = DeltaInfo::new(key, lsn, state);
assert_eq!(delta.log_size(), 11);
}
#[test]
fn test_write_and_read_round_trip() {
let key = b"round_trip_key".to_vec();
let lsn = Lsn::new(10, 20000);
let mut state = SlotState::new();
state.set_dirty();
state.set_known_deleted();
let original = DeltaInfo::new(key, lsn, state);
let mut buffer = Vec::new();
original.write_to_log(&mut buffer);
let (decoded, bytes_consumed) =
DeltaInfo::read_from_log(&buffer).unwrap();
assert_eq!(decoded.key, original.key);
assert_eq!(decoded.lsn, original.lsn);
assert_eq!(decoded.state.as_byte(), original.state.as_byte());
assert_eq!(bytes_consumed, buffer.len());
assert_eq!(bytes_consumed, original.log_size());
}
#[test]
fn test_write_and_read_empty_key() {
let key = Vec::new();
let lsn = NULL_LSN;
let state = SlotState::new();
let original = DeltaInfo::new(key, lsn, state);
let mut buffer = Vec::new();
original.write_to_log(&mut buffer);
let (decoded, _) = DeltaInfo::read_from_log(&buffer).unwrap();
assert!(decoded.key.is_empty());
assert_eq!(decoded.lsn, NULL_LSN);
}
#[test]
fn test_read_from_log_insufficient_data() {
let data = &[0u8; 1];
let result = DeltaInfo::read_from_log(data);
assert!(result.is_err());
}
#[test]
fn test_read_from_log_truncated_key() {
let mut buffer = Vec::new();
buffer.extend_from_slice(&5u16.to_le_bytes()); buffer.extend_from_slice(&[1, 2, 3]);
let result = DeltaInfo::read_from_log(&buffer);
assert!(result.is_err());
assert!(result.unwrap_err().contains("Not enough data for key"));
}
#[test]
fn test_read_from_log_truncated_lsn() {
let mut buffer = Vec::new();
buffer.extend_from_slice(&2u16.to_le_bytes()); buffer.extend_from_slice(&[1, 2]); buffer.extend_from_slice(&[1, 2, 3]);
let result = DeltaInfo::read_from_log(&buffer);
assert!(result.is_err());
assert!(result.unwrap_err().contains("Not enough data for LSN"));
}
#[test]
fn test_clone() {
let key = b"clone_test".to_vec();
let lsn = Lsn::new(7, 7777);
let mut state = SlotState::new();
state.set_embedded_ln();
let delta1 = DeltaInfo::new(key, lsn, state);
let delta2 = delta1.clone();
assert_eq!(delta2.key, delta1.key);
assert_eq!(delta2.lsn, delta1.lsn);
assert_eq!(delta2.state.as_byte(), delta1.state.as_byte());
}
}