Function: allocate_page in b-tree-storage-engine/btree.py

Date: 2026-05-28

Time: 19:20

PageManager.allocate_page

Purpose

allocate_page is the page allocator for a file-backed B-tree storage engine. It returns the page number of a page that's safe to write to — either by recycling a previously freed page or by extending the file with a new one. This is the mechanism that prevents the data file from growing monotonically even as keys are inserted and deleted.

Contract

Preconditions:

Postconditions:

Invariant: After the call, the returned page number will not be returned again by a subsequent allocatepage until it passes through freepage.

Parameters

None (beyond self). The allocator reads all state from the metadata page.

Return Value

Returns an int — the page number that the caller may now write to. The caller is responsible for actually writing valid page data to this slot; allocate_page does not zero or initialize the page contents.

Algorithm

1. Read metadata — fetches the five metadata fields: root, height, totalkeys, nextfree, and free_head.

2. Check the free list (freehead != NOSIBLING):

3. Append a new page (free list is empty):

The two paths are mutually exclusive. The free-list path is preferred when available, keeping the file compact.

Side Effects

Error Handling

There is no explicit error handling. The method assumes:

A corrupted free-list node would silently produce a garbage new_head value, potentially pointing to a live page — this would cause data loss on the next allocation from the free list.

Usage Patterns

Called by BTree._insert during leaf and internal node splits (to get a page for the new right sibling), and by BTree.put when the root itself splits (to allocate a new root page). Typical call pattern:


new_page = self.pm.allocate_page()
data = _serialize_leaf(keys, values, next_sib)
self._wal_write_page(new_page, data)

The caller must write data to the allocated page before the next WAL commit, or the page is "leaked" — allocated in metadata but containing stale/garbage data.

Dependencies

The free-list page layout is coupled to freepage, which writes: HEADERFMT (3 bytes of zeroed header) + 4-byte pointer to the previous head. allocate_page reads from the same offset, so the two methods must agree on this layout or the free list breaks silently.