Page Parsing

Every InnoDB page has a fixed-layout header and trailer that frame the page-type-specific data. The idb::innodb::page module provides types for parsing these structures.

FIL Header

The FilHeader struct represents the 38-byte header present at the start of every InnoDB page.

Byte Layout

Offset  Size  Field
------  ----  -----
0       4     Checksum (or space ID in older formats)
4       4     Page number within the tablespace
8       4     Previous page in doubly-linked list (FIL_NULL = 0xFFFFFFFF if unused)
12      4     Next page in doubly-linked list (FIL_NULL = 0xFFFFFFFF if unused)
16      8     LSN of newest modification to this page
24      2     Page type
26      8     Flush LSN (only meaningful for page 0 of system tablespace)
34      4     Space ID

Parsing

use idb::innodb::page::FilHeader;

// page_data must be at least 38 bytes
let page_data: Vec<u8> = vec![0u8; 16384];
let header = FilHeader::parse(&page_data);

match header {
    Some(hdr) => {
        println!("Page number: {}", hdr.page_number);
        println!("Page type: {}", hdr.page_type);
        println!("LSN: {}", hdr.lsn);
        println!("Space ID: {}", hdr.space_id);
        println!("Checksum: 0x{:08X}", hdr.checksum);
    }
    None => println!("Buffer too small for FIL header"),
}

Fields

FieldTypeDescription
checksumu32Stored checksum (bytes 0-3)
page_numberu32Page number within the tablespace (bytes 4-7)
prev_pageu32Previous page pointer, 0xFFFFFFFF if unused (bytes 8-11)
next_pageu32Next page pointer, 0xFFFFFFFF if unused (bytes 12-15)
lsnu64LSN of newest modification (bytes 16-23)
page_typePageTypePage type enum (bytes 24-25)
flush_lsnu64Flush LSN, only valid on page 0 of system tablespace (bytes 26-33)
space_idu32Space ID this page belongs to (bytes 34-37)

Page Chain Methods

use idb::innodb::page::FilHeader;

let page_data = vec![0u8; 38];
let header = FilHeader::parse(&page_data).unwrap();
// Check if the page has prev/next pointers set
if header.has_prev() {
    println!("Previous page: {}", header.prev_page);
}
if header.has_next() {
    println!("Next page: {}", header.next_page);
}

Both has_prev() and has_next() return false when the pointer is FIL_NULL (0xFFFFFFFF) or 0.

FIL Trailer

The FilTrailer struct represents the 8-byte trailer at the end of every InnoDB page.

Parsing

use idb::innodb::page::FilTrailer;

// The trailer is the last 8 bytes of the page
let page_data: Vec<u8> = vec![0u8; 16384];
let trailer_bytes = &page_data[16384 - 8..];
let trailer = FilTrailer::parse(trailer_bytes);

match trailer {
    Some(trl) => {
        println!("Trailer checksum: 0x{:08X}", trl.checksum);
        println!("Trailer LSN low32: 0x{:08X}", trl.lsn_low32);
    }
    None => println!("Buffer too small for FIL trailer"),
}

Fields

FieldTypeDescription
checksumu32Old-style checksum (bytes 0-3 of trailer)
lsn_low32u32Low 32 bits of the LSN (bytes 4-7 of trailer). Should match the low 32 bits of FilHeader.lsn.

FSP Header

The FspHeader struct represents the FSP (File Space) header found on page 0 of every tablespace, starting at byte offset 38 (immediately after the FIL header).

Parsing

use idb::innodb::tablespace::Tablespace;

let mut ts = Tablespace::open("table.ibd").unwrap();

if let Some(fsp) = ts.fsp_header() {
    println!("Space ID: {}", fsp.space_id);
    println!("Tablespace size: {} pages", fsp.size);
    println!("Free limit: {} pages", fsp.free_limit);
    println!("Flags: 0x{:08X}", fsp.flags);
    println!("Page size from flags: {}", fsp.page_size_from_flags());
}

You can also parse the FSP header directly from a page buffer:

use idb::innodb::page::FspHeader;

// page_data must be a full page 0 buffer
let page_data = vec![0u8; 16384];
let fsp = FspHeader::parse(&page_data);

Fields

FieldTypeDescription
space_idu32Tablespace space ID
sizeu32Tablespace size in pages
free_limitu32Minimum page number not yet initialized
flagsu32Space flags (encodes page size, compression, encryption info)
frag_n_usedu32Number of used pages in the FSP_FREE_FRAG list

Page Size Extraction

use idb::innodb::page::FspHeader;
use idb::innodb::vendor::VendorInfo;

let page_data = vec![0u8; 16384];
let fsp = FspHeader::parse(&page_data).unwrap();

// Auto-detect vendor from flags, then extract page size
let page_size = fsp.page_size_from_flags();

// Or with explicit vendor info
let vendor = VendorInfo::mysql();
let page_size = fsp.page_size_from_flags_with_vendor(&vendor);

PageType

The PageType enum (idb::innodb::page_types::PageType) maps the 2-byte page type field to named variants covering all InnoDB page types from MySQL 5.7 through 9.x, plus MariaDB-specific types.

Parsing

use idb::innodb::page_types::PageType;
use idb::innodb::vendor::VendorInfo;

// Basic parsing (value 18 defaults to SdiBlob / MySQL interpretation)
let pt = PageType::from_u16(17855);
assert_eq!(pt, PageType::Index);

// Vendor-aware parsing (resolves type 18 ambiguity)
let mariadb = VendorInfo::mariadb(idb::innodb::vendor::MariaDbFormat::FullCrc32);
let pt = PageType::from_u16_with_vendor(18, &mariadb);
assert_eq!(pt, PageType::Instant);

let mysql = VendorInfo::mysql();
let pt = PageType::from_u16_with_vendor(18, &mysql);
assert_eq!(pt, PageType::SdiBlob);

Metadata

Each PageType variant provides metadata through three methods:

use idb::innodb::page_types::PageType;

let pt = PageType::Index;
println!("Name: {}", pt.name());              // "INDEX"
println!("Description: {}", pt.description()); // "B+Tree index"
println!("Usage: {}", pt.usage());             // "Table and index data stored in B+Tree structure."

Raw Value

use idb::innodb::page_types::PageType;

let pt = PageType::Index;
let raw: u16 = pt.as_u16();
assert_eq!(raw, 17855);

Common Page Types

VariantValueDescription
Allocated0Freshly allocated, not yet initialized
UndoLog2Undo log page
Inode3File segment inode
FspHdr8File space header (page 0)
Xdes9Extent descriptor
Blob10Uncompressed BLOB data
Sdi17853SDI metadata (MySQL 8.0+)
SdiBlob17854SDI BLOB overflow (MySQL 8.0+)
Index17855B+Tree index page
Rtree17856R-tree spatial index
LobIndex20LOB index (MySQL 8.0+)
LobData21LOB data (MySQL 8.0+)
LobFirst22LOB first page (MySQL 8.0+)
Encrypted15Encrypted page
PageCompressed34354MariaDB page-level compression
Instant18MariaDB instant ALTER (conflicts with SdiBlob in MySQL)