quill_sql/recovery/wal/codec/
txn.rs

1use crate::error::{QuillSQLError, QuillSQLResult};
2use crate::transaction::TransactionId;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5#[repr(u8)]
6pub enum TransactionRecordKind {
7    Begin = 1,
8    Commit = 2,
9    Abort = 3,
10}
11
12impl TransactionRecordKind {
13    pub fn from_u8(value: u8) -> QuillSQLResult<Self> {
14        match value {
15            1 => Ok(TransactionRecordKind::Begin),
16            2 => Ok(TransactionRecordKind::Commit),
17            3 => Ok(TransactionRecordKind::Abort),
18            other => Err(QuillSQLError::Internal(format!(
19                "Unknown transaction record kind: {}",
20                other
21            ))),
22        }
23    }
24}
25
26#[derive(Debug, Clone)]
27pub struct TransactionPayload {
28    pub marker: TransactionRecordKind,
29    pub txn_id: TransactionId,
30}
31
32pub fn encode_transaction(body: &TransactionPayload) -> (u8, Vec<u8>) {
33    let mut buf = Vec::with_capacity(8);
34    buf.extend_from_slice(&body.txn_id.to_le_bytes());
35    (body.marker as u8, buf)
36}
37
38pub fn decode_transaction(bytes: &[u8], info: u8) -> QuillSQLResult<TransactionPayload> {
39    if bytes.len() != 8 {
40        return Err(QuillSQLError::Internal(
41            "Transaction payload must be 8 bytes".to_string(),
42        ));
43    }
44    let txn_id = u64::from_le_bytes(bytes[0..8].try_into().unwrap()) as TransactionId;
45    let marker = TransactionRecordKind::from_u8(info)?;
46    Ok(TransactionPayload { marker, txn_id })
47}