Open-Source Wikis

/

TiDB

/

Systems

/

Domain

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 jobs

Key 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:

  1. The DDL owner advances the cluster's global schema version in etcd.
  2. Every Domain watches that key.
  3. On change, the domain pulls the diff from pkg/meta/ and applies it via infoschema.Builder.ApplyDiff.
  4. The new InfoSchema is 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-Ntopn_slow_query.go. Powers INFORMATION_SCHEMA.CLUSTER_TIDB_TOPN_SLOW_QUERY.
  • Bind info — periodic reload + watch on the mysql.bind_info table.
  • TTL schedulerpkg/ttl/ is wired into Domain. Owner-elected.
  • Runaway query managerrunaway.go reads mysql.tidb_runaway_queries and enforces resource group rules.
  • Historical statshistorical_stats.go snapshots mysql.stats_* for tidb_enable_historical_stats.
  • RU accountingru_stats.go maintains 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 through sessionctx.Context so 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.

Domain – TiDB wiki | Factory