Algorithms · Storage

Write Fast, Merge Later.

A B-tree updates data in place, paying a random disk write per change. The log-structured merge-tree makes a different bet: never update in place. Writes land instantly in a small in-memory memtable; when it fills, it’s flushed to disk as an immutable, sorted SSTable and a fresh memtable takes over. Reads consult the memtable first, then SSTables newest-to-oldest. Old versions pile up until compaction merges files and discards the shadowed ones. Write some keys, watch them flush, then read and compact.

O(1) amortized writes · reads check multiple sorted files · compaction reclaims space
memtable

A small sorted in-memory buffer where every write lands first — no disk seek.

SSTable

A Sorted String Table: an immutable, sorted file flushed from a full memtable.

read path

Check the memtable, then SSTables newest-first; the first hit wins.

compaction

Merge SSTables into fewer, dropping keys shadowed by a newer version.

lsm.js — memtable, SSTables, compaction
Ready
Every write lands in the sorted memtable in memory. When it reaches 4 keys it flushes to an immutable SSTable on disk. Write keys and watch it fill.
0/4
memtable
0
SSTables
last read cost

How it works

The trade the LSM-tree makes is write amplification down, read amplification up. Because writes only ever append to a memtable and later flush sequentially, they avoid the random in-place disk writes a B-tree pays — great for write-heavy workloads. The cost is that one key’s history can be spread across several SSTables, so a read may have to check several files (newest first) before it finds the current value. Compaction is what keeps that number bounded: it merges SSTables and throws away every version shadowed by a newer one.

1

Write → memtable

Each write updates the in-memory memtable, kept sorted by key. No disk seek, so writes are fast and cheap. Updating an existing key just overwrites it in the memtable.

2

Full → flush to an SSTable

When the memtable reaches its size limit, it’s written out sequentially as a new immutable, sorted SSTable, and an empty memtable takes over. Old SSTables are never modified.

3

Read → newest-first

A read checks the memtable, then each SSTable from newest to oldest, stopping at the first match. The newest occurrence of a key is its current value; older copies are stale.

Compaction → merge and prune

Over time, stale versions accumulate across SSTables. Compaction merges SSTables into fewer files, keeping only the newest value per key — reclaiming space and shortening the read path.

Writes
sequential, fast
Read amplification
multiple files
SSTables
immutable, sorted
Used in
RocksDB, Cassandra

The code

# simplified LSM write / read / compact def put(k, v): memtable[k] = v # fast: in-memory, sorted if len(memtable) >= LIMIT: sstables.insert(0, flush(memtable)) # immutable sorted file memtable = SortedDict() def get(k): if k in memtable: return memtable[k] for sst in sstables: # newest -> oldest if k in sst: return sst[k] # first hit is current return None def compact(): # merge, keep newest per key sstables = [merge_keeping_newest(sstables)]

Quick check

1. Why are writes to an LSM-tree fast?

2. A key was written three times over its lifetime. Where is its current value?

3. What does compaction accomplish?

FAQ

What is an LSM-tree?

A write-optimized storage structure. Writes go into an in-memory sorted buffer (memtable); when full it flushes to an immutable sorted file (SSTable). Reads check the memtable then SSTables newest-to-oldest, and compaction merges files while discarding shadowed old versions.

How does an LSM-tree differ from a B-tree?

A B-tree updates in place (a random disk write per update), favoring reads. An LSM-tree never updates in place — it appends to a memtable and flushes sequentially, favoring writes. The trade: LSM reads may check several files (higher read amplification) vs a B-tree’s single path.

What is read amplification in an LSM-tree?

Because a key’s versions spread across the memtable and multiple SSTables, one read may check several places before finding the current value — that extra work is read amplification. Per-SSTable bloom filters (skip files that definitely lack the key) and compaction both reduce it.

Which databases use LSM-trees?

Write-heavy and large-scale stores: RocksDB and LevelDB, Cassandra and ScyllaDB, HBase and Bigtable, and RocksDB-based systems like CockroachDB and TiKV — chosen when write throughput and sequential I/O matter more than the lowest possible read latency.

Keep going

Finished this one? 0 / 98 Algorithms done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More Algorithms