use std::fmt;
pub const LOG_VERSION: u8 = 2;
pub const FIRST_LOG_VERSION: u8 = 1;
const MAX_TYPE_NUM: usize = 128;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum LogEntryType {
FileHeader = 1,
IN = 2,
BIN = 3,
BINDelta = 4,
InsertLN = 10,
UpdateLN = 11,
DeleteLN = 12,
InsertLNTxn = 13,
UpdateLNTxn = 14,
DeleteLNTxn = 15,
MapLN = 20,
NameLN = 21,
NameLNTxn = 22,
FileSummaryLN = 23,
TxnCommit = 30,
TxnAbort = 31,
TxnPrepare = 32,
CkptStart = 40,
CkptEnd = 41,
DbTree = 50,
Trace = 60,
Matchpoint = 61,
RollbackStart = 62,
RollbackEnd = 63,
INDeleteInfo = 64,
INDupDeleteInfo = 65,
OldBINDelta = 66,
OldLN = 67,
DelDupLN = 68,
DupCountLN = 69,
ImmutableFile = 70,
}
impl LogEntryType {
#[inline]
pub fn type_num(self) -> u8 {
self as u8
}
pub fn from_type_num(type_num: u8) -> Option<Self> {
match type_num {
1 => Some(LogEntryType::FileHeader),
2 => Some(LogEntryType::IN),
3 => Some(LogEntryType::BIN),
4 => Some(LogEntryType::BINDelta),
10 => Some(LogEntryType::InsertLN),
11 => Some(LogEntryType::UpdateLN),
12 => Some(LogEntryType::DeleteLN),
13 => Some(LogEntryType::InsertLNTxn),
14 => Some(LogEntryType::UpdateLNTxn),
15 => Some(LogEntryType::DeleteLNTxn),
20 => Some(LogEntryType::MapLN),
21 => Some(LogEntryType::NameLN),
22 => Some(LogEntryType::NameLNTxn),
23 => Some(LogEntryType::FileSummaryLN),
30 => Some(LogEntryType::TxnCommit),
31 => Some(LogEntryType::TxnAbort),
32 => Some(LogEntryType::TxnPrepare),
40 => Some(LogEntryType::CkptStart),
41 => Some(LogEntryType::CkptEnd),
50 => Some(LogEntryType::DbTree),
60 => Some(LogEntryType::Trace),
61 => Some(LogEntryType::Matchpoint),
62 => Some(LogEntryType::RollbackStart),
63 => Some(LogEntryType::RollbackEnd),
64 => Some(LogEntryType::INDeleteInfo),
65 => Some(LogEntryType::INDupDeleteInfo),
66 => Some(LogEntryType::OldBINDelta),
67 => Some(LogEntryType::OldLN),
68 => Some(LogEntryType::DelDupLN),
69 => Some(LogEntryType::DupCountLN),
70 => Some(LogEntryType::ImmutableFile),
_ => None,
}
}
#[inline]
pub fn is_valid(type_num: u8) -> bool {
Self::from_type_num(type_num).is_some()
}
pub fn is_transactional(self) -> bool {
matches!(
self,
LogEntryType::InsertLNTxn
| LogEntryType::UpdateLNTxn
| LogEntryType::DeleteLNTxn
| LogEntryType::NameLNTxn
| LogEntryType::TxnCommit
| LogEntryType::TxnAbort
| LogEntryType::TxnPrepare
)
}
pub fn is_replication_possible(self) -> bool {
matches!(
self,
LogEntryType::InsertLN
| LogEntryType::UpdateLN
| LogEntryType::DeleteLN
| LogEntryType::InsertLNTxn
| LogEntryType::UpdateLNTxn
| LogEntryType::DeleteLNTxn
| LogEntryType::NameLN
| LogEntryType::NameLNTxn
| LogEntryType::TxnCommit
| LogEntryType::TxnAbort
| LogEntryType::Matchpoint
| LogEntryType::Trace )
}
pub fn is_sync_point(self) -> bool {
matches!(
self,
LogEntryType::TxnCommit
| LogEntryType::TxnAbort
| LogEntryType::Matchpoint
)
}
pub fn marshall_inside_latch(self) -> bool {
matches!(
self,
LogEntryType::MapLN
| LogEntryType::FileSummaryLN
| LogEntryType::TxnCommit
| LogEntryType::TxnAbort
| LogEntryType::DbTree
)
}
pub fn is_node_type(self) -> bool {
matches!(
self,
LogEntryType::IN
| LogEntryType::BIN
| LogEntryType::BINDelta
| LogEntryType::InsertLN
| LogEntryType::UpdateLN
| LogEntryType::DeleteLN
| LogEntryType::InsertLNTxn
| LogEntryType::UpdateLNTxn
| LogEntryType::DeleteLNTxn
| LogEntryType::MapLN
| LogEntryType::NameLN
| LogEntryType::NameLNTxn
| LogEntryType::FileSummaryLN
)
}
pub fn is_user_ln_type(self) -> bool {
matches!(
self,
LogEntryType::InsertLN
| LogEntryType::UpdateLN
| LogEntryType::DeleteLN
| LogEntryType::InsertLNTxn
| LogEntryType::UpdateLNTxn
| LogEntryType::DeleteLNTxn
)
}
pub fn is_ln_type(self) -> bool {
matches!(
self,
LogEntryType::InsertLN
| LogEntryType::UpdateLN
| LogEntryType::DeleteLN
| LogEntryType::InsertLNTxn
| LogEntryType::UpdateLNTxn
| LogEntryType::DeleteLNTxn
| LogEntryType::MapLN
| LogEntryType::NameLN
| LogEntryType::NameLNTxn
| LogEntryType::FileSummaryLN
| LogEntryType::OldLN
| LogEntryType::DelDupLN
| LogEntryType::DupCountLN
)
}
pub fn is_in_type(self) -> bool {
matches!(
self,
LogEntryType::IN | LogEntryType::BIN | LogEntryType::BINDelta
)
}
pub fn display_name(self) -> &'static str {
match self {
LogEntryType::FileHeader => "FileHeader",
LogEntryType::IN => "IN",
LogEntryType::BIN => "BIN",
LogEntryType::BINDelta => "BINDelta",
LogEntryType::InsertLN => "INS_LN",
LogEntryType::UpdateLN => "UPD_LN",
LogEntryType::DeleteLN => "DEL_LN",
LogEntryType::InsertLNTxn => "INS_LN_TX",
LogEntryType::UpdateLNTxn => "UPD_LN_TX",
LogEntryType::DeleteLNTxn => "DEL_LN_TX",
LogEntryType::MapLN => "MapLN",
LogEntryType::NameLN => "NameLN",
LogEntryType::NameLNTxn => "NameLN_TX",
LogEntryType::FileSummaryLN => "FileSummaryLN",
LogEntryType::TxnCommit => "Commit",
LogEntryType::TxnAbort => "Abort",
LogEntryType::TxnPrepare => "Prepare",
LogEntryType::CkptStart => "CkptStart",
LogEntryType::CkptEnd => "CkptEnd",
LogEntryType::DbTree => "DbTree",
LogEntryType::Trace => "Trace",
LogEntryType::Matchpoint => "Matchpoint",
LogEntryType::RollbackStart => "RollbackStart",
LogEntryType::RollbackEnd => "RollbackEnd",
LogEntryType::INDeleteInfo => "INDeleteInfo",
LogEntryType::INDupDeleteInfo => "INDupDeleteInfo",
LogEntryType::OldBINDelta => "OldBINDelta",
LogEntryType::OldLN => "OldLN",
LogEntryType::DelDupLN => "DelDupLN",
LogEntryType::DupCountLN => "DupCountLN",
LogEntryType::ImmutableFile => "ImmutableFile",
}
}
}
impl fmt::Display for LogEntryType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.display_name())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_type_num_roundtrip() {
for type_num in 1u8..128 {
if let Some(entry_type) = LogEntryType::from_type_num(type_num) {
assert_eq!(entry_type.type_num(), type_num);
}
}
}
#[test]
fn test_is_valid() {
assert!(LogEntryType::is_valid(1)); assert!(LogEntryType::is_valid(30)); assert!(!LogEntryType::is_valid(100));
assert!(!LogEntryType::is_valid(0));
}
#[test]
fn test_transactional() {
assert!(LogEntryType::TxnCommit.is_transactional());
assert!(LogEntryType::InsertLNTxn.is_transactional());
assert!(!LogEntryType::InsertLN.is_transactional());
assert!(!LogEntryType::IN.is_transactional());
}
#[test]
fn test_replication() {
assert!(LogEntryType::InsertLNTxn.is_replication_possible());
assert!(LogEntryType::TxnCommit.is_replication_possible());
assert!(!LogEntryType::IN.is_replication_possible());
assert!(!LogEntryType::BIN.is_replication_possible());
}
#[test]
fn test_sync_point() {
assert!(LogEntryType::TxnCommit.is_sync_point());
assert!(LogEntryType::Matchpoint.is_sync_point());
assert!(!LogEntryType::InsertLNTxn.is_sync_point());
}
#[test]
fn test_node_types() {
assert!(LogEntryType::BIN.is_in_type());
assert!(LogEntryType::IN.is_in_type());
assert!(LogEntryType::InsertLN.is_user_ln_type());
assert!(!LogEntryType::MapLN.is_user_ln_type());
}
#[test]
fn test_marshall_inside_latch() {
assert!(LogEntryType::MapLN.marshall_inside_latch());
assert!(LogEntryType::FileSummaryLN.marshall_inside_latch());
assert!(LogEntryType::TxnCommit.marshall_inside_latch());
assert!(LogEntryType::TxnAbort.marshall_inside_latch());
assert!(LogEntryType::DbTree.marshall_inside_latch());
assert!(!LogEntryType::BIN.marshall_inside_latch());
assert!(!LogEntryType::IN.marshall_inside_latch());
assert!(!LogEntryType::InsertLNTxn.marshall_inside_latch());
assert!(!LogEntryType::Trace.marshall_inside_latch());
}
#[test]
fn test_display_name_and_display_trait() {
for type_num in 1u8..128 {
if let Some(entry_type) = LogEntryType::from_type_num(type_num) {
let name = entry_type.display_name();
assert!(!name.is_empty(), "display_name should not be empty");
assert_eq!(format!("{}", entry_type), name);
}
}
}
#[test]
fn test_is_node_type_coverage() {
for t in [
LogEntryType::IN,
LogEntryType::BIN,
LogEntryType::BINDelta,
LogEntryType::InsertLN,
LogEntryType::UpdateLN,
LogEntryType::DeleteLN,
LogEntryType::InsertLNTxn,
LogEntryType::UpdateLNTxn,
LogEntryType::DeleteLNTxn,
LogEntryType::MapLN,
LogEntryType::NameLN,
LogEntryType::NameLNTxn,
LogEntryType::FileSummaryLN,
] {
assert!(t.is_node_type(), "{} should be a node type", t);
}
for t in [
LogEntryType::FileHeader,
LogEntryType::TxnCommit,
LogEntryType::TxnAbort,
LogEntryType::TxnPrepare,
LogEntryType::CkptStart,
LogEntryType::CkptEnd,
LogEntryType::DbTree,
LogEntryType::Trace,
LogEntryType::Matchpoint,
LogEntryType::RollbackStart,
LogEntryType::RollbackEnd,
LogEntryType::INDeleteInfo,
LogEntryType::INDupDeleteInfo,
LogEntryType::OldBINDelta,
LogEntryType::OldLN,
LogEntryType::DelDupLN,
LogEntryType::DupCountLN,
LogEntryType::ImmutableFile,
] {
assert!(!t.is_node_type(), "{} should not be a node type", t);
}
}
#[test]
fn test_from_type_num_exhaustive() {
let mut found = 0usize;
for n in 0u8..=255 {
match LogEntryType::from_type_num(n) {
Some(t) => {
assert_eq!(t.type_num(), n);
found += 1;
}
None => {
assert!(!LogEntryType::is_valid(n));
}
}
}
assert_eq!(found, 31);
}
}