use wbase::store_type::REPLAY_TASK_ACCESS_VECTOR_BYTES;
use super::{AofHeader, write_at};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AofShardedHeader {
pub basic: AofHeader,
pub sequence_number: i64,
}
impl AofShardedHeader {
pub const TOTAL_SIZE: usize = AofHeader::TOTAL_SIZE + 8;
#[inline]
pub const fn to_bytes(&self) -> [u8; Self::TOTAL_SIZE] {
let mut out = [0u8; Self::TOTAL_SIZE];
write_at(&mut out, 0, self.basic.to_bytes());
write_at(
&mut out,
AofHeader::TOTAL_SIZE,
self.sequence_number.to_le_bytes(),
);
out
}
#[inline]
pub const fn parse(entry: &[u8]) -> Option<Self> {
let Some(chunk) = entry.first_chunk::<{ Self::TOTAL_SIZE }>() else {
return None;
};
let Some(basic) = AofHeader::parse(chunk) else {
return None;
};
let seq = i64::from_le_bytes([
chunk[16], chunk[17], chunk[18], chunk[19], chunk[20], chunk[21], chunk[22], chunk[23],
]);
Some(Self {
basic,
sequence_number: seq,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AofSingleLogTransactionHeader {
pub basic: AofHeader,
pub participant_count: i16,
pub replay_task_access_vector: [u8; REPLAY_TASK_ACCESS_VECTOR_BYTES],
}
impl AofSingleLogTransactionHeader {
pub const TOTAL_SIZE: usize = AofHeader::TOTAL_SIZE + 2 + REPLAY_TASK_ACCESS_VECTOR_BYTES;
#[inline]
pub const fn to_bytes(&self) -> [u8; Self::TOTAL_SIZE] {
let mut out = [0u8; Self::TOTAL_SIZE];
write_at(&mut out, 0, self.basic.to_bytes());
write_at(
&mut out,
AofHeader::TOTAL_SIZE,
self.participant_count.to_le_bytes(),
);
write_at(
&mut out,
AofHeader::TOTAL_SIZE + 2,
self.replay_task_access_vector,
);
out
}
#[inline]
pub const fn parse(entry: &[u8]) -> Option<Self> {
let Some(chunk) = entry.first_chunk::<{ Self::TOTAL_SIZE }>() else {
return None;
};
let Some(basic) = AofHeader::parse(chunk) else {
return None;
};
let (_, tail) = chunk.split_at(AofHeader::TOTAL_SIZE);
let Some((p_bytes, rest)) = tail.split_first_chunk::<2>() else {
return None;
};
let Some((vector, _)) = rest.split_first_chunk::<REPLAY_TASK_ACCESS_VECTOR_BYTES>() else {
return None;
};
Some(Self {
basic,
participant_count: i16::from_le_bytes(*p_bytes),
replay_task_access_vector: *vector,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AofShardedLogTransactionHeader {
pub sharded: AofShardedHeader,
pub participant_count: i16,
pub replay_task_access_vector: [u8; REPLAY_TASK_ACCESS_VECTOR_BYTES],
}
impl AofShardedLogTransactionHeader {
pub const TOTAL_SIZE: usize = AofShardedHeader::TOTAL_SIZE + 2 + REPLAY_TASK_ACCESS_VECTOR_BYTES;
#[inline]
pub const fn to_bytes(&self) -> [u8; Self::TOTAL_SIZE] {
let mut out = [0u8; Self::TOTAL_SIZE];
write_at(&mut out, 0, self.sharded.to_bytes());
write_at(
&mut out,
AofShardedHeader::TOTAL_SIZE,
self.participant_count.to_le_bytes(),
);
write_at(
&mut out,
AofShardedHeader::TOTAL_SIZE + 2,
self.replay_task_access_vector,
);
out
}
#[inline]
pub const fn parse(entry: &[u8]) -> Option<Self> {
let Some(chunk) = entry.first_chunk::<{ Self::TOTAL_SIZE }>() else {
return None;
};
let Some(sharded) = AofShardedHeader::parse(chunk) else {
return None;
};
let (_, tail) = chunk.split_at(AofShardedHeader::TOTAL_SIZE);
let Some((p_bytes, rest)) = tail.split_first_chunk::<2>() else {
return None;
};
let Some((vector, _)) = rest.split_first_chunk::<REPLAY_TASK_ACCESS_VECTOR_BYTES>() else {
return None;
};
Some(Self {
sharded,
participant_count: i16::from_le_bytes(*p_bytes),
replay_task_access_vector: *vector,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::aof::header::AofHeaderType;
#[test]
fn test_aof_sharded_header_roundtrip() {
let mut basic = AofHeader::new();
basic.set_header_type(AofHeaderType::ShardedHeader);
basic.store_version = 100;
basic.session_id = 42;
let sharded = AofShardedHeader {
basic,
sequence_number: 999_888_777,
};
let bytes = sharded.to_bytes();
assert_eq!(bytes.len(), AofShardedHeader::TOTAL_SIZE);
let parsed = AofShardedHeader::parse(&bytes).unwrap();
assert_eq!(parsed, sharded);
assert_eq!(parsed.sequence_number, 999_888_777);
}
#[test]
fn test_aof_transaction_headers_roundtrip() {
let mut basic = AofHeader::new();
basic.set_header_type(AofHeaderType::SingleLogTransactionHeader);
let mut vector = [0u8; REPLAY_TASK_ACCESS_VECTOR_BYTES];
vector[0] = 0xAA;
vector[31] = 0x55;
let single_txn = AofSingleLogTransactionHeader {
basic,
participant_count: 8,
replay_task_access_vector: vector,
};
let bytes_single = single_txn.to_bytes();
assert_eq!(
bytes_single.len(),
AofSingleLogTransactionHeader::TOTAL_SIZE
);
let parsed_single = AofSingleLogTransactionHeader::parse(&bytes_single).unwrap();
assert_eq!(parsed_single, single_txn);
assert_eq!(parsed_single.participant_count, 8);
assert_eq!(parsed_single.replay_task_access_vector[0], 0xAA);
assert_eq!(parsed_single.replay_task_access_vector[31], 0x55);
let mut sharded_basic = AofHeader::new();
sharded_basic.set_header_type(AofHeaderType::ShardedLogTransactionHeader);
let sharded = AofShardedHeader {
basic: sharded_basic,
sequence_number: 123456,
};
let sharded_txn = AofShardedLogTransactionHeader {
sharded,
participant_count: 16,
replay_task_access_vector: vector,
};
let bytes_sharded = sharded_txn.to_bytes();
assert_eq!(
bytes_sharded.len(),
AofShardedLogTransactionHeader::TOTAL_SIZE
);
let parsed_sharded = AofShardedLogTransactionHeader::parse(&bytes_sharded).unwrap();
assert_eq!(parsed_sharded, sharded_txn);
}
}