The In-Memory Illusion: B-Trees vs. B+ Trees
Many developers, particularly those accustomed to web development, might start their journey into lower-level systems by building an in-memory key-value store. This is often the first step toward understanding the mechanics behind systems like Redis, or the persistence layers of databases like MySQL and PostgreSQL. Initially, a simple in-memory B-tree might seem like the logical choice. It offers logarithmic time complexity for search, insert, and delete operations, which is a significant improvement over linear scans.
However, the reality of modern database systems is more nuanced. While B-trees are fundamental, databases typically employ a variation: the B+ tree. The key difference lies in how data is stored. In a standard B-tree, data can be stored in both internal nodes and leaf nodes. In a B+ tree, all actual data records are stored exclusively in the leaf nodes. Internal nodes act purely as index nodes, directing searches to the appropriate leaf nodes. This design optimizes for range queries and sequential access, as all data is contiguous at the leaf level, and leaf nodes are typically linked together.
The author of the source material initially implemented an in-memory B-tree, then iterated to a B+ tree. This transition highlights a common learning curve: understanding that the data structures powering large-scale, persistent systems are not always the most intuitive or the first ones encountered. The B+ tree's structure, while seemingly more complex in its separation of index and data, is a direct consequence of optimizing for disk I/O, a constraint not present in pure in-memory structures.

The Disk Bottleneck: Why Order Breaks Down
The core insight from building a B+ tree storage engine, especially when considering disk persistence, is understanding the fundamental limitations and characteristics of magnetic disk drives and even SSDs. Unlike RAM, which offers relatively uniform access times regardless of data location, disk I/O is characterized by significant latency. This latency is dominated by seek time (for HDDs) and rotational latency, or controller overhead and flash translation layer (for SSDs), though the latter is much smaller than HDDs. Reading a single byte from disk can be orders of magnitude slower than reading it from RAM.
This disparity in access speed is why database systems are meticulously designed to minimize disk I/O. The B+ tree's structure is a direct response to this. Each node in a B+ tree is typically sized to match the disk's block size or page size (e.g., 4KB, 8KB, 16KB). This ensures that when a node is read from disk, the maximum amount of relevant index information is brought into memory in a single operation. A larger node fanout means fewer levels in the tree, and thus fewer disk reads to find a specific record.
Consider a typical scenario: searching for a key. In memory, traversing a balanced binary search tree might involve a few dozen pointer dereferences. On disk, if each node were small, you might need hundreds or thousands of individual disk seeks. A B+ tree, with its high fanout (meaning each node can have many children), drastically reduces the tree's height. For a database with billions of records, a B+ tree might only have 3-5 levels. This means that finding any record requires only a handful of disk reads, each reading a full page of index data.
The counterintuitive part is how the concept of "order" changes. In memory, we think of order in terms of comparisons and traversal paths. On disk, order is about spatial locality and minimizing the number of distinct I/O operations. A B+ tree maintains logical order for efficient traversal, but its physical layout on disk is dictated by page boundaries and the need to pack as much branching information as possible into each page to reduce the number of pages that need to be read.
Beyond In-Memory: Pages, WAL, and Persistence
When moving from an in-memory B+ tree to a disk-based storage engine, several new concepts become critical. The first is the idea of pages. As mentioned, nodes are mapped to fixed-size pages on disk. When a page is needed for reading or writing, it's loaded into a buffer pool (a cache in memory). If the page is modified, it's marked as dirty. The database then needs a strategy to ensure these dirty pages are eventually written back to disk reliably.
This leads to the concept of Write-Ahead Logging (WAL). Instead of directly modifying pages in the buffer pool and hoping they get written to disk before a crash, WAL ensures durability. Before any data page is modified in memory, the intended changes are first written to a sequential log file (the WAL). If the system crashes, it can replay the WAL upon restart to reconstruct the state of the data pages up to the point of the crash. This is a fundamental technique for ensuring transactional integrity and crash recovery in databases. It's a far cry from the simple file persistence of a web application, where overwriting a file might be sufficient.
The author's exploration into pages and WAL signifies a crucial shift in perspective. It's no longer about just the algorithmic efficiency of data structures but about managing the physical constraints of storage hardware and ensuring data safety and consistency in the face of potential failures. The B+ tree, while an elegant in-memory structure, becomes the foundation for a much larger, more complex system when adapted for disk persistence, demanding considerations like page management, buffer caching, and robust recovery mechanisms.

The Unanswered Question: Scalability of B+ Tree Implementations
As developers delve deeper into building storage engines, a significant question emerges: how do different B+ tree implementations scale with varying disk technologies and workloads? While the core principles of B+ trees and disk page management are well-established, the practical performance characteristics can diverge significantly. For instance, how does a B+ tree designed for spinning HDDs perform on NVMe SSDs, and what tuning is required? Furthermore, what are the trade-offs between different page sizes, fanout factors, and caching strategies for diverse application profiles—read-heavy, write-heavy, or mixed workloads?
The journey from an in-memory B+ tree to a disk-based storage engine is not merely an academic exercise; it's a pragmatic necessity for anyone building systems that need to store and retrieve data reliably and efficiently. It forces a re-evaluation of what "performance" means when the primary bottleneck shifts from CPU cycles to I/O operations. The B+ tree, with its high fanout and focus on contiguous leaf nodes, is a testament to how fundamental data structures evolve to meet the challenges of their underlying hardware, proving that sometimes, the most efficient path on disk is not the most direct one in memory.
