use crate::ln::Ln;
#[derive(Debug, Clone)]
pub struct MapLn {
ln: Ln,
db_id: u64,
deleted: bool,
is_transient: bool,
}
impl MapLn {
pub fn new(db_id: u64, config_data: Vec<u8>) -> Self {
MapLn {
ln: Ln::new(Some(config_data)),
db_id,
deleted: false,
is_transient: false,
}
}
pub fn get_db_id(&self) -> u64 {
self.db_id
}
pub fn is_deleted(&self) -> bool {
self.deleted
}
pub fn set_deleted(&mut self, deleted: bool) {
self.deleted = deleted;
self.ln.set_dirty();
}
pub fn is_transient(&self) -> bool {
self.is_transient
}
pub fn set_transient(&mut self, transient: bool) {
self.is_transient = transient;
self.ln.set_dirty();
}
pub fn get_ln(&self) -> &Ln {
&self.ln
}
pub fn get_ln_mut(&mut self) -> &mut Ln {
&mut self.ln
}
pub fn log_size(&self) -> usize {
self.ln.log_size() + 8 + 1 + 1 }
pub fn write_to_log(&self, buf: &mut Vec<u8>) {
self.ln.write_to_log(buf);
buf.extend_from_slice(&self.db_id.to_be_bytes());
buf.push(if self.deleted { 1 } else { 0 });
buf.push(if self.is_transient { 1 } else { 0 });
}
pub fn read_from_log(buf: &[u8]) -> std::io::Result<Self> {
let ln = Ln::read_from_log(buf)?;
let ln_size = ln.log_size();
let remaining = &buf[ln_size..];
use byteorder::{BigEndian, ReadBytesExt};
use std::io::Cursor;
let mut cursor = Cursor::new(remaining);
let db_id = cursor.read_u64::<BigEndian>()?;
let deleted = cursor.read_u8()? != 0;
let is_transient = cursor.read_u8()? != 0;
Ok(MapLn { ln, db_id, deleted, is_transient })
}
}
impl std::fmt::Display for MapLn {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"<mapln db_id={} deleted={} transient={}>",
self.db_id, self.deleted, self.is_transient
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use noxu_util::Vlsn;
#[test]
fn test_map_ln_new() {
let config = b"database config data".to_vec();
let map_ln = MapLn::new(42, config.clone());
assert_eq!(map_ln.get_db_id(), 42);
assert!(!map_ln.is_deleted());
assert!(!map_ln.is_transient());
assert_eq!(map_ln.get_ln().get_data(), Some(config.as_slice()));
}
#[test]
fn test_map_ln_roundtrip() {
let config = b"test config".to_vec();
let mut map_ln = MapLn::new(100, config.clone());
map_ln.get_ln_mut().set_vlsn(Vlsn::new(50));
let mut buf = Vec::new();
map_ln.write_to_log(&mut buf);
let map_ln2 = MapLn::read_from_log(&buf).unwrap();
assert_eq!(map_ln2.get_db_id(), 100);
assert!(!map_ln2.is_deleted());
assert!(!map_ln2.is_transient());
assert_eq!(map_ln2.get_ln().get_data(), Some(config.as_slice()));
assert_eq!(map_ln2.get_ln().get_vlsn().sequence(), 50);
}
#[test]
fn test_map_ln_deleted() {
let config = b"config".to_vec();
let mut map_ln = MapLn::new(200, config);
assert!(!map_ln.is_deleted());
map_ln.set_deleted(true);
assert!(map_ln.is_deleted());
assert!(map_ln.get_ln().is_dirty());
let mut buf = Vec::new();
map_ln.write_to_log(&mut buf);
let map_ln2 = MapLn::read_from_log(&buf).unwrap();
assert_eq!(map_ln2.get_db_id(), 200);
assert!(map_ln2.is_deleted());
assert!(!map_ln2.is_transient());
}
#[test]
fn test_map_ln_transient() {
let config = b"transient config".to_vec();
let mut map_ln = MapLn::new(300, config);
assert!(!map_ln.is_transient());
map_ln.set_transient(true);
assert!(map_ln.is_transient());
assert!(map_ln.get_ln().is_dirty());
let mut buf = Vec::new();
map_ln.write_to_log(&mut buf);
let map_ln2 = MapLn::read_from_log(&buf).unwrap();
assert_eq!(map_ln2.get_db_id(), 300);
assert!(!map_ln2.is_deleted());
assert!(map_ln2.is_transient());
}
#[test]
fn test_map_ln_both_flags() {
let config = b"config".to_vec();
let mut map_ln = MapLn::new(400, config);
map_ln.set_deleted(true);
map_ln.set_transient(true);
let mut buf = Vec::new();
map_ln.write_to_log(&mut buf);
let map_ln2 = MapLn::read_from_log(&buf).unwrap();
assert_eq!(map_ln2.get_db_id(), 400);
assert!(map_ln2.is_deleted());
assert!(map_ln2.is_transient());
}
#[test]
fn test_map_ln_log_size() {
let config = b"test".to_vec();
let map_ln = MapLn::new(500, config);
let size = map_ln.log_size();
let mut buf = Vec::new();
map_ln.write_to_log(&mut buf);
assert_eq!(size, buf.len());
}
#[test]
fn test_map_ln_display() {
let config = b"config".to_vec();
let map_ln = MapLn::new(600, config);
let s = format!("{}", map_ln);
assert!(s.contains("db_id=600"));
assert!(s.contains("deleted=false"));
assert!(s.contains("transient=false"));
}
}