Skip to main content

Catalog Manager — Physical Storage Format

This page provides a byte-level breakdown of the binary .dat files used by the Catalog Manager. Since these files cannot be inspected as plain text, understanding the binary structure is essential for debugging and verification.

RookDB system catalogs use the identical slotted-page storage format as user tables, ensuring consistency across the storage engine.


1. File Structure Overview

Each catalog file (e.g., pg_table.dat) is composed of fixed-size 8,192-byte pages.

Page IndexTypePurpose
0Header PageStores global metadata (e.g., total page count).
1+Data PageStores tuple data using a slotted layout.

2. Header Page (Page 0) Layout

The first page of every catalog file acts as the table header.

Byte OffsetSizeNameDescription
0–34page_countTotal number of pages in the file (u32, Little-Endian).
4–81918188ReservedUnused space, zero-filled.

3. Data Page (Slotted Page) Layout

Every data page (Page 1 onwards) follows the PostgreSQL-inspired slotted-page layout.

Byte OffsetSizeNameDescription
0–34lowerPointer to the start of free space (u32 LE). Also the end of the Item ID array.
4–74upperPointer to the end of free space (u32 LE). Also the start of the latest tuple data.
8 to lowervarItem IDsArray of 8-byte identifiers for every tuple on the page.
lower to uppervarFree SpaceUnallocated bytes.
upper to 8191varTuple DataThe actual serialized catalog records, growing backwards.

Item Identifier (8 bytes)

Each entry in the Item IDs array describes one slot on the page.

Byte OffsetSizeNameDescription
0–34offsetOffset from the start of the page to the tuple data (u32 LE).
4–74lengthByte length of the tuple (u32 LE). 0 indicates a logically deleted tuple.

4. Tuple Serialization Format

Catalog records are serialized into variable-length byte slices.

Basic Types

TypeBytesFormat
u8 / i81Direct byte
u16 / i162Little-Endian
u32 / i324Little-Endian
u64 / i648Little-Endian
bool10x01 for true, 0x00 for false

Variable-Length Types

TypeStructureDescription
String[len: u16 LE] [bytes]A 2-byte length prefix followed by UTF-8 bytes.
Array[count: u16 LE] [items]A 2-byte count prefix followed by N serialized items.

5. Worked Example: pg_database Record

Consider a record for the system database (db_oid=1, owner="rookdb", encoding=1):

Binary Breakdown (Serialised Tuple)

OffsetBytesMeaningValue
0-301 00 00 00db_oid1
4-506 00db_name length6
6-1173 79 73 74 65 6ddb_name bytes"system"
12-1306 00owner length6
14-1972 6f 6f 6b 64 62owner bytes"rookdb"
20-27XX XX XX XX XX XX XX XXcreated_atTimestamp
2801encoding1 (UTF-8)

Page Insertion State

If this was the first record on Page 1:

  1. Header: lower = 16 (Page Header (8) + 1 Item ID (8)), upper = 8163 (8192 - 29).
  2. Item ID 0: offset = 8163, length = 29.
  3. Data: Bytes 8163–8191 contain the tuple shown above.

6. Inspecting .dat Files

To manually inspect these files, you can use a hex editor or utility like hexdump:

# View the global header (Page 0)
hexdump -C -n 8 database/global/catalog_pages/pg_table.dat

# View the start of Page 1 (Data Page Header)
hexdump -C -s 8192 -n 16 database/global/catalog_pages/pg_table.dat