quill_sql/recovery/wal/codec/
page.rs

1use crate::buffer::PageId;
2use crate::error::{QuillSQLError, QuillSQLResult};
3use crate::recovery::Lsn;
4
5#[derive(Debug, Clone)]
6pub struct PageWritePayload {
7    pub page_id: PageId,
8    pub prev_page_lsn: Lsn,
9    pub page_image: Vec<u8>,
10}
11
12#[derive(Debug, Clone)]
13pub struct PageDeltaPayload {
14    pub page_id: PageId,
15    pub prev_page_lsn: Lsn,
16    pub offset: u16,
17    pub data: Vec<u8>,
18}
19
20pub fn encode_page_write(body: &PageWritePayload) -> Vec<u8> {
21    // Page/PageWrite (rmid=Page, info=0)
22    // body: page_id(4) + prev_page_lsn(8) + image_len(4) + page_image[]
23    let mut buf = Vec::with_capacity(4 + 8 + 4 + body.page_image.len());
24    buf.extend_from_slice(&body.page_id.to_le_bytes());
25    buf.extend_from_slice(&body.prev_page_lsn.to_le_bytes());
26    buf.extend_from_slice(&(body.page_image.len() as u32).to_le_bytes());
27    buf.extend_from_slice(&body.page_image);
28    buf
29}
30
31pub fn encode_page_delta(body: &PageDeltaPayload) -> Vec<u8> {
32    // Page/PageDelta (rmid=Page, info=1)
33    // body: page_id(4) + prev_page_lsn(8) + offset(2) + len(4) + data[]
34    let mut buf = Vec::with_capacity(4 + 8 + 2 + 4 + body.data.len());
35    buf.extend_from_slice(&body.page_id.to_le_bytes());
36    buf.extend_from_slice(&body.prev_page_lsn.to_le_bytes());
37    buf.extend_from_slice(&body.offset.to_le_bytes());
38    buf.extend_from_slice(&(body.data.len() as u32).to_le_bytes());
39    buf.extend_from_slice(&body.data);
40    buf
41}
42
43pub fn decode_page_write(bytes: &[u8]) -> QuillSQLResult<PageWritePayload> {
44    if bytes.len() < 4 + 8 + 4 {
45        return Err(QuillSQLError::Internal(
46            "PageWrite payload too short".to_string(),
47        ));
48    }
49    let page_id = u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as PageId;
50    let prev_page_lsn = u64::from_le_bytes(bytes[4..12].try_into().unwrap()) as Lsn;
51    let image_len = u32::from_le_bytes(bytes[12..16].try_into().unwrap()) as usize;
52    if bytes.len() != 16 + image_len {
53        return Err(QuillSQLError::Internal(
54            "PageWrite payload length mismatch".to_string(),
55        ));
56    }
57    let page_image = bytes[16..].to_vec();
58    Ok(PageWritePayload {
59        page_id,
60        prev_page_lsn,
61        page_image,
62    })
63}
64
65pub fn decode_page_delta(bytes: &[u8]) -> QuillSQLResult<PageDeltaPayload> {
66    if bytes.len() < 4 + 8 + 2 + 4 {
67        return Err(QuillSQLError::Internal(
68            "PageDelta payload too short".to_string(),
69        ));
70    }
71    let page_id = u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as PageId;
72    let prev_page_lsn = u64::from_le_bytes(bytes[4..12].try_into().unwrap()) as Lsn;
73    let offset = u16::from_le_bytes(bytes[12..14].try_into().unwrap());
74    let data_len = u32::from_le_bytes(bytes[14..18].try_into().unwrap()) as usize;
75    if bytes.len() != 18 + data_len {
76        return Err(QuillSQLError::Internal(
77            "PageDelta payload length mismatch".to_string(),
78        ));
79    }
80    let data = bytes[18..].to_vec();
81    Ok(PageDeltaPayload {
82        page_id,
83        prev_page_lsn,
84        offset,
85        data,
86    })
87}