Skip to main content

sqlrite/sql/pager/
page.rs

1//! Page layout primitives.
2//!
3//! Every database file is a sequence of fixed-size pages. Page 0 holds the
4//! `DbHeader`; every other page is a typed, chained payload container.
5//!
6//! Layout of a non-header page (`PAGE_SIZE` bytes total):
7//! ```text
8//!   0..1      PageType tag   (u8)
9//!   1..5      next-page      (u32 LE; 0 = end of chain)
10//!   5..7      payload length (u16 LE; bytes used in the payload area)
11//!   7..end    payload bytes
12//! ```
13
14use crate::error::{Result, SQLRiteError};
15
16/// Size of every page in bytes. SQLite's default too — small enough to fit
17/// in one disk sector group, large enough to carry meaningful payload.
18pub const PAGE_SIZE: usize = 4096;
19
20/// Bytes consumed by the per-page header (type + next-ptr + payload-len).
21pub const PAGE_HEADER_SIZE: usize = 7;
22
23/// Usable payload bytes per page after subtracting the header.
24pub const PAYLOAD_PER_PAGE: usize = PAGE_SIZE - PAGE_HEADER_SIZE;
25
26/// Identifies what kind of content a page holds.
27///
28/// Phase 3c retired the `SchemaRoot` tag (tag value `1`) because the
29/// schema catalog is now stored as a regular table (`sqlrite_master`)
30/// with leaf pages. Tag `1` remains reserved so future variants don't
31/// alias it.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33#[repr(u8)]
34pub enum PageType {
35    /// Leaf page of a table — holds a slot directory and cells.
36    TableLeaf = 2,
37    /// Continuation page carrying the spilled body of an oversized cell.
38    Overflow = 3,
39    /// Interior B-Tree node — holds a slot directory of dividers pointing
40    /// at child pages plus a rightmost-child pointer in the payload header.
41    InteriorNode = 4,
42}
43
44impl PageType {
45    // Used by integrity-check paths. Direct `page_buf[0] == TableLeaf as u8`
46    // compares are how current call sites check page types.
47    #[allow(dead_code)]
48    pub fn from_u8(v: u8) -> Result<PageType> {
49        match v {
50            2 => Ok(PageType::TableLeaf),
51            3 => Ok(PageType::Overflow),
52            4 => Ok(PageType::InteriorNode),
53            other => Err(SQLRiteError::Internal(format!(
54                "unknown page type tag {other}"
55            ))),
56        }
57    }
58}
59
60// The actual encoding/decoding of a page into/out of a `PAGE_SIZE`-byte
61// buffer lives in `pager/mod.rs`; those helpers used to live here but were
62// inlined once the `Pager` took over raw byte I/O.