pingcap/tidb
Domain
A Domain is the per-TiDB-instance object that holds the long-lived runtime state: the active infoschema, the statistics handle, the binding manager, slow-query top-N, the runaway-query controller, the TTL job scheduler, and many other background workers.
Purpose
pkg/domain/ exists because a TiDB process is not a single global state — there is one Domain per kv.Storage (i.e., per cluster the process is connected to). The domain:
- Watches schema and statistics changes in TiKV/etcd and refreshes in-memory caches.
- Owns the goroutines that load infoschema diffs, refresh stats, evict the plan cache, capture plan replayer dumps, etc.
- Provides the central handle every session asks for the current infoschema and stats handles.
- Coordinates with
pkg/owner/for leader-elected background tasks (DDL owner, stats owner, autoanalyse owner).
Most TiDB processes have exactly one Domain, but tests routinely create multiple.
Directory layout
pkg/domain/
├── domain.go # The Domain struct and most of its lifecycle (≈99 KB)
├── domain_sysvars.go # Sysvar reload behaviour
├── extract.go # Extract / load helpers for plan replayer
├── plan_replayer.go # Plan replayer state, scheduling, capture handle
├── plan_replayer_dump.go # Bundle a plan replayer file
├── ru_stats.go # Resource-unit accounting per resource group
├── runaway.go # Runaway query controller
├── schema_checker.go # Cross-statement schema-version checker
├── sysvar_cache.go # Cluster-wide sysvar cache
├── topn_slow_query.go # In-memory top-N slow queries
├── historical_stats.go # Periodic snapshot of stats for time travel
├── domainctx.go # Per-domain context attached to every session
├── globalconfigsync/ # Sync TiDB global configs to PD
├── infosync/ # Cluster info advertised to PD (instance address, labels, …)
├── crossks/ # Cross-keyspace helpers
├── affinity/ # Affinity policies for replicas
├── metrics/ # Per-domain Prometheus metrics
├── serverinfo/ # TiDB instance info (used in CLUSTER_INFO)
└── sqlsvrapi/ # Internal SQL API used by background jobsKey abstractions
| Type | File | Purpose |
|---|---|---|
domain.Domain |
pkg/domain/domain.go |
The whole subsystem. Created by domain.NewDomain and stored as a singleton per kv.Storage. |
domain.InfoSchema() |
same | Returns the current infoschema.InfoSchema. |
domain.StatsHandle() |
same | Returns the active pkg/statistics/handle.Handle. |
domain.BindHandle() |
same | Returns the SQL binding manager (pkg/bindinfo). |
domain.PlanReplayerHandle() |
pkg/domain/plan_replayer.go |
Manages plan-replayer captures. |
domain.RunawayManager() |
pkg/domain/runaway.go |
Tracks queries exceeding resource budgets. |
domain.SysVarCache |
pkg/domain/sysvar_cache.go |
Cluster-wide sysvar values, refreshed periodically and on etcd notifications. |
domain.InfoSyncer |
pkg/domain/infosync/ |
Publishes the local TiDB's info to PD (heartbeat, labels). |
domain.SchemaChecker |
pkg/domain/schema_checker.go |
Per-statement schema-version drift detection. |
How Domain wires itself up
graph TD start[domain.NewDomain] --> init[Init] init --> infosync[InfoSyncer<br/>register with PD] init --> sysvar[SysVarCache reload] init --> infoschema[Initial InfoSchema load] init --> stats[StatsHandle init] init --> ddl[Bind DDL owner] init --> sched[Background goroutines] sched --> reload[Schema-version watcher] sched --> stat[Stats refresh / autoanalyze] sched --> bind[Bindinfo refresh] sched --> plan[Plan-replayer capture] sched --> ttl[TTL scheduler] sched --> runaway[Runaway scanner] sched --> historical[Historical stats]
domain.Init is called from cmd/tidb-server/main.go. It registers the instance with PD, starts the infoschema watcher (etcd tidb/ddl/global_schema_version), starts the stats handle, and spawns the bookkeeping goroutines listed above.
Many of these workers are leader-elected via pkg/owner/. For example, autoanalyze runs on a single owner per cluster to avoid duplicate work.
Schema reload
The schema reload loop is the heartbeat of the system:
- The DDL owner advances the cluster's global schema version in etcd.
- Every
Domainwatches that key. - On change, the domain pulls the diff from
pkg/meta/and applies it viainfoschema.Builder.ApplyDiff. - The new
InfoSchemais swapped atomically; new sessions immediately see it; in-flight sessions keep their snapshot until the next statement starts.
domain.SchemaChecker is what detects "schema changed under me" mid-statement: planner-bound infoschema is compared with the current one before commit; on conflict, the statement aborts with a recoverable error.
Background services owned by Domain
- Stats refresh (
StatsHandle.Update,StatsHandle.GCStats) — periodic. - Auto-analyze — owner-only; uses
pkg/statistics/handle/autoanalyze/. - Plan replayer — periodic GC of expired bundles, plus capture handle for
tidb_capture_plan_baselines. - Slow query top-N —
topn_slow_query.go. PowersINFORMATION_SCHEMA.CLUSTER_TIDB_TOPN_SLOW_QUERY. - Bind info — periodic reload + watch on the
mysql.bind_infotable. - TTL scheduler —
pkg/ttl/is wired into Domain. Owner-elected. - Runaway query manager —
runaway.goreadsmysql.tidb_runaway_queriesand enforces resource group rules. - Historical stats —
historical_stats.gosnapshotsmysql.stats_*fortidb_enable_historical_stats. - RU accounting —
ru_stats.gomaintains per-resource-group RU usage. - Cluster info syncer (
infosync/) — announces our instance to PD, including labels for placement.
Integration points
- Session (
pkg/session/) — every session opens with a reference to its Domain. - DDL (
pkg/ddl/) — Domain owns the DDL handle and starts the worker. - Statistics (
pkg/statistics/handle/) — owned by Domain. - Bindinfo (
pkg/bindinfo/) — owned by Domain. - Owner (
pkg/owner/) — Domain registers the elections it cares about. - Plugins/extensions — Domain hands them the current infoschema/sysvar snapshot.
Entry points for modification
- New cluster-wide background job → spawn it from
domain.Init, gate it on owner election if it must run only once. - New cluster-wide cache → register a watcher on the relevant etcd path or a periodic reload similar to
sysvar_cache.go. - New "give me X for the current cluster" accessor → add a method on
Domain, then plumb throughsessionctx.Contextso callers don't reach for a global.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.