CockroachDB — Patterns#
Sampling note#
CockroachDB is an XL-tier project (~9,000+ Go files). Pattern detection was performed with grep across the full repository, then key files were read for depth. Packages sampled in depth: pkg/util/stop, pkg/kv/kvclient/kvcoord (TxnCoordSender interceptors), pkg/kv/kvserver/scheduler.go, pkg/util/ctxgroup, pkg/base/testing_knobs.go, pkg/util/syncutil, pkg/sql/conn_executor.go (FSM), pkg/testutils/hook.go. Counts are from full-repo grep, excluding vendor/.
Concurrency patterns#
Stopper — Coordinated Goroutine Lifecycle#
- Usage: Universal across the entire codebase. 303 calls to
stopper.RunAsyncTask/stopper.RunWorker. Every long-lived goroutine is managed through this mechanism. - Example:
pkg/util/stop/stopper.go—Stopperwraps aquotapool-based semaphore for async task throttling and async.WaitGrouptracking all active tasks. - Pattern: Callers invoke
stopper.RunAsyncTask(ctx, "task-name", func(ctx context.Context) {...}). The stopper provides a derived context that is cancelled when shutdown begins. Onstopper.Stop(), it cancels all contexts and waits for all tasks to finish.stopper.WithCancelOnQuiesce(ctx)lets non-task code also honour drain. TheErrUnavailablesentinel is returned if a new task is submitted after quiesce begins. - Assessment: Highly idiomatic and effective for a server process with complex shutdown ordering. Significantly more structured than bare
sync.WaitGroup+context.WithCancelpatterns. The task-name argument enables debugging viastopper.HandleDebugHTTP endpoint. The semaphore throttling (ErrThrottled) adds back-pressure without goroutine explosion.
raftScheduler — Sharded Priority Worker Pool#
- Usage:
pkg/kv/kvserver/scheduler.go. One pool per Store; processes all Raft events for all ranges hosted on that store. - Example:
type raftScheduler struct { processor raftProcessor shards []*raftSchedulerShard // shard 0 = priority, rest = round-robin by RangeID priorityIDs syncutil.Set[roachpb.RangeID] done sync.WaitGroup } type raftSchedulerShard struct { syncutil.Mutex cond *sync.Cond queue rangeIDQueue[queuedRangeID] state map[roachpb.RangeID]raftScheduleState numWorkers int } - Pattern: Ranges are assigned to shards by
RangeID % (numShards - 1)(shard 0 is reserved for priority ranges, such as liveness range). Workers block onsync.Cond.Wait()within their shard. The deduplication state map (state map[RangeID]raftScheduleState) prevents redundant Raft ticks from queuing multiple times for the same range — a key optimization when thousands of ranges exist on one store. - Assessment: A sophisticated, production-grade worker pool pattern. The sharding approach trades memory for lock contention reduction at high worker counts. Priority routing via a dedicated shard is uncommon in open-source Go and worth studying for latency-sensitive background work.
ctxgroup — errgroup with Explicit Context Discipline#
- Usage:
pkg/util/ctxgroup/ctxgroup.go. Used throughout for fan-out concurrent operations. - Example:
g := ctxgroup.WithContext(ctx) g.GoCtx(func(ctx context.Context) error { // ctx is explicitly passed — no shadowed variable risk return api.Call(ctx, val) }) return g.Wait() // GroupWorkers convenience: return ctxgroup.GroupWorkers(ctx, numWorkers, func(ctx context.Context, workerID int) error {...}) - Pattern:
ctxgroup.WithContextdoes NOT return a new context (unlike stdliberrgroup.WithContext), forcing callers to receive ctx explicitly inGoCtx. The package documentation explains the specific bugs this prevents: context variable shadowing causing use-after-cancel in a large codebase.GroupWorkersfurther reduces boilerplate for homogeneous worker pools. - Assessment: An excellent example of wrapping a stdlib/x package to enforce a discipline. The bug examples in the package doc are taken from real CockroachDB incidents. Projects with large teams benefit significantly from this approach.
Root/Leaf Transaction Split (Distributed Fan-out)#
- Usage:
pkg/kv/sender.go,pkg/kv/kvclient/kvcoord. Used during DistSQL query execution to distribute a single ACID transaction across multiple nodes. - Pattern:
// pkg/kv/sender.go type TxnType int const ( RootTxn TxnType = iota // owns intent tracking, commit LeafTxn // accumulates intents, returns to Root at merge ) type TxnSender interface { GetLeafTxnInputState(ctx context.Context, ...) (*roachpb.LeafTxnInputState, error) GetLeafTxnFinalState(ctx context.Context) (*roachpb.LeafTxnFinalState, error) UpdateRootWithLeafFinalState(ctx context.Context, tfs *roachpb.LeafTxnFinalState) ... } - Mechanism: The gateway node creates a
RootTxn. Each remote DistSQL worker receives aLeafTxnInputStatesnapshot and operates on aLeafTxn. On completion, the leaf returnsLeafTxnFinalState(accumulated write intents, span refreshes) to the root, which merges it before commit. This enables parallel reads and writes across nodes within a single serializable transaction without sharing a*kv.Txnobject (which is not goroutine-safe). - Assessment: Unique to CockroachDB in open-source Go. The Root/Leaf split is the correct solution to distributed transaction fan-out and avoids the naive (and incorrect) alternative of shared mutable transaction state.
Channel Fan-out with select (2437 channels, 1716 selects)#
- Usage: Pervasive throughout the codebase for async event delivery, pipeline stages, and coordination.
- Example:
pkg/kv/kvserver/store_raft.go— incoming Raft messages arrive on a channel; theraftSchedulerusessync.Cond-based notification internally to avoid the overhead of a select per range. - Assessment: Standard Go concurrency; CockroachDB applies it at scale. The
sync.Condpreference in the scheduler over channels reflects a performance trade-off for high-frequency events.
Context Propagation (26,543 usages)#
- Usage: Every function that does I/O, RPC, or can block accepts
context.Contextas its first parameter — a strict discipline enforced project-wide. - Assessment: Exemplary context discipline. CockroachDB was an early adopter and the codebase demonstrates correct context threading even in deeply nested call chains. The
ctxgrouppattern above reinforces this discipline.
Graceful Drain (Stopper + serverController)#
- Usage:
pkg/server/drain.go,pkg/server/server_controller.go. Multi-tenant aware drain that callsgracefulDrain()on each active server (system + tenant) in sequence. - Pattern:
stopper.WithCancelOnQuiesce(ctx)creates contexts that cancel when the server enters quiesce mode. SQL connections are politely drained: active transactions are given a window to commit before connections are forcibly closed.sqlServer.gracefulDrainCompleteis an atomic bool signalling completion. - Assessment: Correct multi-phase drain (stop accepting new work → drain in-flight → hard stop) implemented consistently.
Error handling#
- Style: Custom error library (
github.com/cockroachdb/errors) with rich structured annotations and PostgreSQL SQLSTATE codes. 3,380 imports of the library across the codebase. - Error categories:
- Assertion failures (
errors.AssertionFailedf) — 4,949 usages. Used for internal invariant violations (the equivalent ofpanicbut recoverable and logged with full stack). These are programming errors, not expected runtime errors. - Structured user-facing errors —
errors.WithHint,errors.WithDetail,errors.WithIssueLink(547 usages combined). Errors surfaced to SQL clients carry a hint (what to do), a detail (what went wrong), and optionally a link to a GitHub issue. This maps to PostgreSQL’sHINTandDETAILerror fields. - PostgreSQL SQLSTATE codes —
pgerror.WithCandidateCode(err, pgcode.X)(3,188 usages). Every SQL error must carry a SQLSTATE code for PostgreSQL wire compatibility. TheWithCandidateCodefunction attaches a “candidate” code that can be overridden further up the stack. - Standard wrapping —
errors.Wrap,errors.Wrapf,fmt.Errorfwith%wfor adding context during propagation.
- Assertion failures (
- Error types defined:
kvpb.NodeUnavailableError,roachpb.RangeNotFoundError,roachpb.WriteIntentError,roachpb.TransactionRetryError,roachpb.AmbiguousResultError, and many more — defined as protobuf messages so they can be transmitted over the wire and reconstructed on the client side. Theerrors.Is/errors.Aschain works through these protobuf-transmitted errors via customMarkhelpers. - Circuit breaker errors:
pkg/kv/kvserver/replica_circuit_breaker.gowrapscockroachdb/circuitbreaker. When a replica’s liveness probe fails, the breaker trips and requests immediately returncircuit.ErrBreakerOpeninstead of hanging indefinitely. - Examples:
pkg/cli/clierror/formatted_error.go: extractspgcode, hint, and detail from any error and formats it for the CLI user — demonstrates the full structured error extraction path.pkg/kv/kvpb/batch.go:408:errors.AssertionFailedffor invariant violation in batch processing.
Configuration pattern#
Approach: Two-tier — Static flags + Dynamic cluster settings#
- Static (startup): Cobra persistent flags bound to
base.Configandserver.Configstructs, withpkg/util/envutilprovidingCOCKROACH_*environment variable overrides for each flag default. - Dynamic (cluster settings):
pkg/settingsregistry with 1,056RegisterXxxSettingcalls (bool, int, float, string, duration, byte-size). Settings are declared as typed package-level variables and initialized at program start. Operators change them viaSET CLUSTER SETTINGSQL, which propagates to all nodes via gossip + KV writes. Thecluster.Settingsstruct carries asettings.Valuescontainer; every component that needs a setting receives*cluster.Settings(not individual settings values), so new settings can be added without changing call sites. - Example:
// pkg/rpc/settings.go var enableRPCCircuitBreakers = settings.RegisterBoolSetting( settings.SystemOnly, "rpc.circuit_breaker.enabled", "enable circuit breakers for RPC connections", true, ) // Usage: enableRPCCircuitBreakers.Get(&settings.SV) - Assessment: The cluster settings pattern is one of CockroachDB’s most important and most reusable patterns. It separates “what the setting is” (declaration) from “how to change it” (SQL DDL) and “how to read it” (typed accessor), with zero-restart runtime propagation. It is far superior to env-var or flag reloading for long-lived processes.
TestingKnobs — Structured Test Injection#
- Approach:
base.TestingKnobs(55+ fields) carries per-moduleModuleTestingKnobsinterfaces. Components receive a*base.TestingKnobsat construction and use nil-checks to activate test behaviour. - Example:
// pkg/base/testing_knobs.go type TestingKnobs struct { Store ModuleTestingKnobs KVClient ModuleTestingKnobs SQLExecutor ModuleTestingKnobs // ... 50+ more fields } type ModuleTestingKnobs interface { ModuleTestingKnobs() } // marker - Pattern: Each package defines its own
testing_knobs.gowith a concreteTestingKnobsstruct that has function-typed fields for injecting faults, interceptors, and timing hooks. Production code checksif cfg.TestingKnobs.Store != nil { knobs := cfg.TestingKnobs.Store.(*kvserver.StoreTestingKnobs) }. The//go:build !testtag is never used — these knobs are in production code but optimized away by the compiler when nil. - Assessment: This pattern enables fine-grained fault injection without reflection or build tags. The central
base.TestingKnobsstruct with typed slots prevents knobs from proliferating as ad-hoc global variables. The 1,155 usages outside test files demonstrate how deeply testing concerns are woven into the production path.
Dependency injection#
- Approach: Manual wiring. No DI framework (no
wire,dig, orfx). - Evidence:
pkg/server/server.goNewServer()is ~1,200 lines of explicit construction. Every dependency is wired by hand, in dependency order, with constructor functions returning both a value and an error. - CCL injection via
init()hooks: The most distinctive DI pattern. Core packages (e.g.,pkg/jobs/metrics.go) declare function-variable hooks initialized tonil:CCL packages override these in their// pkg/jobs/metrics.go var MakeChangefeedMetricsHook func(time.Duration, *cidr.Lookup) metric.Struct var MakeBackupMetricsHook func(time.Duration) metric.Structinit()functions:The commercial binary’s// pkg/ccl/changefeedccl/metrics.go (approximate) func init() { jobs.MakeChangefeedMetricsHook = makeChangefeedMetrics }main.gohas a single blank import_ "github.com/cockroachdb/cockroach/pkg/ccl"which triggers the entire CCLinit()chain. The OSS binary omits this import; hooks remain nil; features are absent. - TestingHook utility:Used in tests to temporarily replace package-level function variables (e.g.,
// pkg/testutils/hook.go func TestingHook(ptr, val interface{}) func() { global := reflect.ValueOf(ptr).Elem() orig := reflect.New(global.Type()).Elem() orig.Set(global) global.Set(reflect.ValueOf(val)) return func() { global.Set(orig) } } // Go 1.18+ generic version: func HookGlobal[T any](ptr *T, val T) func() { ... }defer testutils.TestingHook(&getCurrentTime, func() time.Time {...})()). This makes the CCL hook pattern testable. - Assessment: The init()-hook pattern is architecturally elegant for an OSS/enterprise split but has implicit ordering: CCL init() runs before main(), so hooks are always set before use. The
TestingHookutility makes this injection point testable and is generalized for any package-level variable replacement. The lack of a DI framework is deliberate — manual wiring is explicit, and in a large codebase, the explicitness outweighs the boilerplate.
Other notable patterns#
txnInterceptor Chain (Stack-allocated Middleware)#
- File:
pkg/kv/kvclient/kvcoord/txn_coord_sender.go - Pattern:
TxnCoordSendermaintains a chain of 7txnInterceptorimplementations for cross-cutting transaction concerns. All 7 are embedded in a singleinterceptorAllocstruct to avoid separate heap allocations:Each interceptor implementsinterceptorAlloc struct { arr [7]txnInterceptor // the chain, ordered from outermost to innermost txnHeartbeater // keeps transaction alive txnSeqNumAllocator // assigns sequence numbers to requests txnWriteBuffer // buffers writes until commit (reduces round-trips) txnPipeliner // async write pipelining through Raft txnCommitter // handles commit protocol details txnSpanRefresher // refreshes read spans on serialization failure txnMetricRecorder // records transaction metrics txnLockGatekeeper // not in chain array; manages lock table interaction }lockedSender(SendLocked(context.Context, *BatchRequest) (*BatchResponse, *Error)) andsetWrapped(lockedSender)to form a chain. A request traverses all interceptors before reachingDistSender. - Assessment: An elegant combination of the middleware/chain-of-responsibility pattern with Go’s struct embedding to avoid heap fragmentation. The embedding within
interceptorAllocmeans aTxnCoordSenderallocation brings all 7 interceptors into the same memory block. Adding new cross-cutting concerns (e.g., the write buffer was added later) requires only adding a new struct and inserting it into the chain, with no changes to the other interceptors.
optgen — DSL-driven Code Generation for Optimizer Rules#
- Files:
pkg/sql/opt/norm/rules/*.opt,pkg/sql/opt/xform/rules/*.opt,pkg/sql/optgen/ - Pattern: CockroachDB’s query optimizer transformation rules are written in a custom DSL called
optgen(optimizer generator). Rules look like:
The# pkg/sql/opt/norm/rules/agg.opt [EliminateAggDistinct, Normalize] (AggDistinct $input:(Min | Max | BoolAnd | BoolOr)) => $inputoptgencompiler reads.optfiles and generates Go code (*_gen.gofiles) implementing thememo.Memodata structures, the Cascades exploration engine, and the rule dispatch tables. This keeps rule logic concise (pattern matching syntax) while generating efficient Go code. - Assessment: Rare in open-source Go databases. Most use hand-written rule tables or imperative optimizer code. The
optgenapproach allows non-Go programmers to contribute optimizer rules and keeps the rule count manageable (~500 rules). The tradeoff is a custom build step and a non-standard toolchain.
Explicit FSM for SQL Transaction State (connExecutor)#
- File:
pkg/sql/conn_executor.go(5000+ lines),pkg/sql/txn_state.go - Pattern: Each SQL connection’s transaction lifecycle is managed by an explicit finite state machine using the
pkg/util/fsmpackage. States includestateNoTxn,stateOpen,stateAborted,stateRestartWait,stateCommitWait. Transitions are triggered by SQL events (eventTxnStart,eventTxnCommit,eventTxnRollback,eventNonRetriableErr,eventRetriableErr, etc.). Type switches onex.machine.CurState()implement state-specific behaviour:case stateOpen: return ex.execStmtInOpenState(ctx, ast, res) case stateAborted: return ex.execStmtInAbortedState(ctx, ast, res) - Assessment: Using an explicit, typed FSM for protocol state (rather than boolean flags) makes the transaction lifecycle verifiable and auditable. The
fsmpackage ensures only valid transitions are taken;TransitionNotFoundErrormakes illegal state transitions visible at runtime. This pattern is appropriate for any complex protocol that must handle partial failures correctly.
syncutil — Instrumented Mutex with Build-tag Variants#
- Package:
pkg/util/syncutil/ - Pattern: CockroachDB replaces
sync.Mutexwithsyncutil.Mutexthroughout the codebase. Three implementations are compiled via build tags:mutex_sync.go— thin wrapper aroundsync.Mutex(default, zero overhead)mutex_deadlock.go(//go:build deadlock) — wrapsgithub.com/sasha-s/go-deadlockwith 5-minute timeout for deadlock detection in CImutex_tracing.go— addsTracedLock(ctx)that emits a trace event if lock acquisition is slow, andTimedLock()returning duration
- Assessment: A mature multi-implementation pattern that allows development/production tradeoffs without
#ifdef. TheAssertHeld()method (on some variants) enables documentation-as-enforcement of “must be called under X lock” invariants. The naming convention*MuLocked(1,384 usages inkvserver) for functions that assert the caller holds a lock is a disciplined commenting convention thatAssertHeld()can eventually enforce.
baseQueue — Template for Raft Maintenance Background Work#
- Package:
pkg/kv/kvserver, files:*_queue.go - Pattern: CockroachDB has ~10 background queues (
mvccGCQueue,mergeQueue,splitQueue,replicateQueue,raftLogQueue, etc.) that process replicas periodically. Each embedsbaseQueuewhich provides: priority queue, rate limiting, metrics, and the dispatch loop. Each concrete queue implements:shouldQueue(ctx, now, replica, confReader) (shouldQueue bool, priority float64) process(ctx, replica, confReader) (processed bool, err error) - Assessment: A clean template method pattern in Go via interface embedding. The
shouldQueue/processsplit is elegant: the framework handles scheduling priority and rate limiting, the concrete queue handles only domain logic. Adding a new maintenance concern requires only implementing two methods.
Registry Pattern for Jobs and Cloud Backends#
- Examples:
pkg/jobs— job types register aResumerfactory byjobspb.Typeenumpkg/cloud/externalconn/impl_registry.go— external connection types register byFactoryTypepkg/sql/sem/builtins/— SQL built-in functions registered in maps
- Pattern:
// pkg/cloud/externalconn/impl_registry.go var factoryFactories = map[FactoryType]func(connectionpb.ConnectionProvider) connectionParserFactory{} func RegisterConnectionDetailsFromURIFactory(t FactoryType, f func(...) connectionParserFactory) { factoryFactories[t] = f } - Assessment: Standard registry pattern for extensible dispatch. CockroachDB uses it in preference to large
switchstatements for runtime extensibility. CCL packages register additional job types and cloud backends into these registries duringinit().
Functional Options (selective usage)#
- Usage: Not universal — used for test utilities, CLI options, and some client packages. About 50
func With*patterns found. - Example:
pkg/backup/backuptestutils/testutils.go—WithParams,WithBank,WithInitFunc,WithTempDiretc. for composable test cluster setup.pkg/roachprod/promhelperclient/client.go—WithIAPTokenSource,WithCustomURL. - Assessment: CockroachDB uses functional options where appropriate (optional parameters, test configuration) but does not apply them universally. The majority of core construction uses explicit structs (
StoreConfig,DistSenderConfig) with zero values as defaults — a style preference that trades functional-options elegance for explicit visibility of all options.
datadriven Testing#
- Usage: 718
datadriven.usages in test files.pkg/testutils/datadriven(or the externalgithub.com/cockroachdb/datadriven) implements file-based golden tests. - Pattern: Test files contain commands and expected output. The test function reads the file, executes each command, and diffs actual vs. expected output. Updating expected output is done by re-running with
-rewrite. - Assessment: Highly effective for SQL query testing, optimizer rule testing, and any system with human-readable output. Reduces test verbosity for large output comparisons and makes diff-based review natural. Used throughout the optimizer and SQL packages.
Pattern summary#
| Pattern | Location | Scale | Book-worthy? |
|---|---|---|---|
Stopper goroutine lifecycle | pkg/util/stop | 303 usages | ★★★ — universal goroutine management |
raftScheduler sharded worker pool | pkg/kv/kvserver/scheduler.go | 1 per Store | ★★★ — priority + sharding for high throughput |
ctxgroup errgroup discipline | pkg/util/ctxgroup | Widespread | ★★★ — prevents real bugs; shows wrapper value |
| Root/Leaf transaction split | pkg/kv/sender.go | DistSQL fan-out | ★★★ — unique distributed concurrency pattern |
txnInterceptor chain (stack-allocated) | pkg/kv/kvclient/kvcoord | 7 interceptors | ★★★ — middleware + allocation optimization |
| Cluster settings registry | pkg/settings | 1,056 settings | ★★★ — runtime-reconfigurable without restart |
TestingKnobs structured injection | pkg/base/testing_knobs.go | 55+ fields | ★★★ — disciplined test injection at scale |
init()-hook CCL injection | pkg/ccl, pkg/jobs/metrics.go | ~15 hooks | ★★★ — OSS/enterprise split without build tags |
cockroachdb/errors structured errors | Throughout | 3,380 imports | ★★ — hint/detail/SQLSTATE annotation |
errors.AssertionFailedf | Throughout | 4,949 usages | ★★ — assertion-as-error for invariant violations |
syncutil.Mutex build-tag variants | pkg/util/syncutil | Throughout | ★★ — deadlock detection / tracing by build tag |
optgen DSL → code generation | pkg/sql/opt | ~500 rules | ★★ — rare pattern for optimizer rules |
| FSM for SQL state | pkg/sql/conn_executor.go | 1 per connection | ★★ — typed FSM for protocol correctness |
TestingHook/HookGlobal | pkg/testutils/hook.go | Widespread | ★★ — package-global injection for tests |
baseQueue template for background work | pkg/kv/kvserver/*_queue.go | ~10 queues | ★ — standard template method |
datadriven golden tests | Throughout SQL/optimizer | 718 usages | ★★ — highly effective for SQL output testing |