etcd-io/etcd
MVCC store
Source: server/storage/mvcc/.
Purpose
mvcc is etcd's user-facing data layer. Every key holds a history of revisions, not a single value. Reads can specify a revision to time-travel; watchers stream every event after a chosen revision; compactions discard history older than a chosen point. The same package owns the watcher implementation.
Directory layout
server/storage/mvcc/
├── kv.go, kv_view.go # KV interface and read/write views
├── kvstore.go # store struct, currentRev, compactMainRev
├── kvstore_txn.go # store TXNs
├── kvstore_compaction.go # compaction worker
├── store.go # public Store factory
├── revision.go # main+sub revision arithmetic
├── index.go, key_index.go # in-memory btree mapping key -> revisions
├── watchable_store.go # adds watch fan-out on top of store
├── watchable_store_txn.go
├── watcher.go, watcher_group.go
├── hash.go # MVCC hashing for cluster-wide consistency check
├── metrics.go, metrics_txn.go
├── testutil/
└── ...Key abstractions
| Symbol | File | Description |
|---|---|---|
KV interface |
server/storage/mvcc/kv.go |
The contract every EtcdServer uses for storage |
store |
server/storage/mvcc/kvstore.go |
Bbolt-backed implementation; tracks currentRev, compactMainRev |
index (treeIndex) |
server/storage/mvcc/index.go |
In-memory btree of keyIndex per key |
keyIndex |
server/storage/mvcc/key_index.go |
Per-key revision history with generations |
revision |
server/storage/mvcc/revision.go |
{main, sub} 16-byte encoded |
watchableStore |
server/storage/mvcc/watchable_store.go |
Adds synced/unsynced watcher groups + sync goroutine |
watcherGroup |
server/storage/mvcc/watcher_group.go |
Interval-tree of watchers indexed by key range |
HashStorage |
server/storage/mvcc/hash.go |
Periodically computes and stores hashes of the keyspace for corruption detection |
Sentinels:
ErrCompacted— requested revision is older thancompactMainRev.ErrFutureRev— requested revision is greater thancurrentRev.
How it works
graph TD
txn[Apply Txn] --> w[Write txn]
w --> idx[treeIndex.Put / Tombstone]
w --> backend[(bbolt backend)]
backend --> w
idx --> w
w --> hash[HashStorage]
w --> notify[watchableStore.notify]
notify --> watchers[active watchers]A write transaction:
- Acquires
store.muandstore.revMu. - Bumps
currentRev(mainincrements,subincrements per op within the txn). - Encodes each new value into bbolt under the bucket key
<main>_<sub>and updates the in-memory index. - Computes a watcher delta and publishes events to
watchableStore.
A read transaction snapshots the current revision and reads from bbolt at that snapshot. Range queries traverse the in-memory index in the requested key range and pull values from bbolt.
Compaction runs in the background:
- The compactor (
server/etcdserver/api/v3compactor/) callsstore.Compact(rev). - The store walks the index, marks revisions
<= revas removable, and removes them in batches (defaultCompactionBatchLimit = 1000). - The work yields between batches via a FIFO scheduler from
pkg/scheduleto avoid blocking writes.
Watch fan-out
watchableStore keeps two groups:
synced— caught up withcurrentRev; receive events vianotify.unsynced— replaying older revisions; thesyncWatchersLooppumps them forward.
Watcher cancellation, fragmentation, and progress notifications are handled by watcher.go / watcher_group.go. The interval tree from pkg/adt/ makes range overlap checks O(log n).
Hashing
HashStorage keeps a rolling hash of the keyspace for cluster-wide corruption detection. The compactor and the membership system kick consistency checks via server/etcdserver/corrupt.go.
Integration points
- Backend:
server/storage/backend/(bbolt) for the actual persistence. - Lease: each KV may attach a lease ID; deletion of a lease drives
mvcc.DeleteRangefor all keys. - Apply:
server/etcdserver/apply/andserver/etcdserver/txn/drive every mutation. - Watch RPC:
server/etcdserver/api/v3rpc/watch.gotranslatesmvcc.WatchStreaminto the gRPCWatchservice. - Compactor:
server/etcdserver/api/v3compactor/drives periodic + revision-based compaction.
Entry points for modification
- New range option (e.g. count-only behavior) →
kvstore_txn.go::Rangeandkv.go::RangeOptions. - New watcher capability →
watcher.go,watchable_store.go, plus the gRPC handler. - Tuning compaction → constants in
kvstore.go(defaultCompactionBatchLimit,defaultCompactionSleepInterval). - Hashing changes need careful coordination — see
Documentation/postmortems/for what happens when they go wrong.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.