postgres/postgres
Architecture
PostgreSQL is a process-per-connection relational database server. A single supervisor process — the postmaster — listens on a TCP socket (and a Unix-domain socket) and forks a dedicated backend for each client connection. All backends and auxiliary processes share a region of System V / POSIX shared memory that holds the buffer pool, the lock tables, the proc array, and other coordination structures.
This page sketches the system at three layers: the process model, the in-memory layout, and the request pipeline.
Process model
The postmaster's only job is supervision: it forks children, restarts them after crashes, and routes signals. It never touches shared memory itself, which keeps it isolated from buffer-pool corruption when a backend crashes.
graph TD
Postmaster["postmaster<br/>(src/backend/postmaster/postmaster.c)"]
Postmaster -->|fork| Backend1["backend<br/>(per client connection)"]
Postmaster -->|fork| Backend2[backend]
Postmaster -->|fork| WALWriter["WAL writer"]
Postmaster -->|fork| BgWriter["background writer"]
Postmaster -->|fork| Checkpointer["checkpointer"]
Postmaster -->|fork| Autovacuum["autovacuum launcher<br/>+ workers"]
Postmaster -->|fork| WalSender["wal senders<br/>(replication)"]
Postmaster -->|fork| LogicalRep["logical replication<br/>launcher + workers"]
Postmaster -->|fork| Logger["syslogger"]
Backend1 -.->|reads/writes| Shmem[(Shared memory<br/>buffer pool, locks, proc array, WAL buffers)]
Backend2 -.-> Shmem
WALWriter -.-> Shmem
BgWriter -.-> Shmem
Checkpointer -.-> Shmem
Autovacuum -.-> Shmem
WalSender -.-> ShmemThe auxiliary processes are launched and respawned by the postmaster but do specialized work:
| Process | Source | Role |
|---|---|---|
| Backend | src/backend/tcop/postgres.c |
One per connection. Runs the SQL main loop. |
| WAL writer | src/backend/postmaster/walwriter.c |
Asynchronously flushes WAL buffers. |
| Checkpointer | src/backend/postmaster/checkpointer.c |
Periodically writes a consistency snapshot to disk. |
| Background writer | src/backend/postmaster/bgwriter.c |
Writes dirty buffers ahead of evictions. |
| Autovacuum | src/backend/postmaster/autovacuum.c |
Launches vacuum/analyze workers based on table activity. |
| Stats collector | src/backend/utils/activity/ |
Gathers cumulative statistics (now in shared memory, no separate process since v15). |
| WAL sender / receiver | src/backend/replication/walsender.c, walreceiver.c |
Streaming replication endpoints. |
| Logical rep launcher | src/backend/replication/logical/launcher.c |
Spawns per-subscription apply workers. |
Shared memory layout
All cooperative state lives in a single shared-memory segment created by the postmaster at startup. Major regions:
- Buffer pool (
src/backend/storage/buffer/) — fixed-size pages (default 8 KB) cached from disk. Replacement is a clock-sweep algorithm. - Lock tables (
src/backend/storage/lmgr/) — heavyweight (relation/row) locks plus lightweight latches used inside the engine. - ProcArray (
src/backend/storage/ipc/procarray.c) — list of all live backends with their current XID and snapshot horizons. The visibility checker scans this on every tuple test. - WAL buffers (
src/backend/access/transam/xlog.c) — ring of pages flushed topg_wal/. - CLOG / commit log (
src/backend/access/transam/clog.c) — per-XID commit/abort status, paged into shared SLRU caches. - Shared catalog cache invalidation (
src/backend/utils/cache/inval.c) — propagates DDL invalidations to peer backends.
A backend allocates from its own MemoryContext tree (see src/backend/utils/mmgr/). The top context is TopMemoryContext; queries run inside ExecutorContext and PortalContext, which are reset between statements.
Request pipeline
A client query travels through a fixed sequence of subsystems:
graph LR
Client -->|libpq frontend protocol| Backend
Backend --> Parser["Parser<br/>(src/backend/parser)"]
Parser --> Analyzer["Parse analysis<br/>analyze.c"]
Analyzer --> Rewriter["Rewriter<br/>(src/backend/rewrite)"]
Rewriter --> Planner["Planner / Optimizer<br/>(src/backend/optimizer)"]
Planner --> Executor["Executor<br/>(src/backend/executor)"]
Executor --> AM["Access methods<br/>heap, btree, gin, gist, brin, ..."]
AM --> Buffer["Buffer manager<br/>+ smgr"]
Buffer --> Disk[(disk / WAL)]
Executor -->|tuples| Backend
Backend -->|results| ClientThe stages:
- Parse.
src/backend/parser/gram.y(a bison grammar) turns SQL text into a raw parse tree ofNodestructs (seesrc/backend/nodes/).parse_analyzeresolves names against the catalog and produces aQuerytree. - Rewrite. Views and rules transform the
Query(src/backend/rewrite/rewriteHandler.c). - Plan. The planner enumerates access paths and join orders, costs them, and emits a
PlannedStmt(a tree ofPlannodes). Top-level entry:standard_plannerinsrc/backend/optimizer/plan/planner.c. The geometric/genetic optimizer (GEQO) handles large joins. - Execute. The executor walks the plan tree pulling tuples on demand. Each plan node has matching exec code (e.g.,
nodeSeqscan.c,nodeHashjoin.c). Tuples come from the access methods, which read pages through the buffer manager. - Storage. Pages are 8 KB blocks. Heap tuples store row data; index access methods (B-tree, GIN, GiST, SP-GiST, BRIN, hash) maintain their own page formats. All page modifications are logged to WAL before they are flushed.
Top-level dispatch lives in src/backend/tcop/postgres.c (PostgresMain, exec_simple_query, exec_parse_message, etc.). This file is the front door from the wire protocol to the rest of the engine.
MVCC and concurrency
Reads do not block writes and writes do not block reads. PostgreSQL uses multi-version concurrency control: each row version carries xmin/xmax transaction IDs, and a transaction's snapshot is the set of XIDs visible to it. Visibility checks live in src/backend/utils/time/ (e.g., tqual.c is now heapam_visibility.c) and src/backend/access/heap/heapam_visibility.c. Old row versions are reclaimed by VACUUM.
Heavyweight locks (relation, row, advisory) are managed by the lock manager (src/backend/storage/lmgr/lock.c); deadlocks are detected via a wait-for graph (deadlock.c). Lightweight locks (LWLocks) protect shared-memory data structures; src/backend/storage/lmgr/lwlock.c.
See MVCC and transactions for the full treatment.
Durability and recovery
Every change to a buffer page is preceded by a WAL record (src/backend/access/transam/xlog.c). WAL is written sequentially to pg_wal/ and fsync'd at commit (or grouped, depending on synchronous_commit). On crash recovery, the startup process replays WAL from the last checkpoint forward to rebuild the consistent state. WAL is also the substrate for streaming replication: a WAL sender on the primary ships records to a WAL receiver on the replica, which replays them.
See WAL and recovery and Replication for details.
Where to look next
| You want to know about... | Page |
|---|---|
| How a query is parsed and planned | Parser, Planner |
| How the executor pulls tuples | Executor |
| Heap, index AMs, table AM API | Access methods |
| Buffer pool, smgr, file layer | Storage |
| WAL records and crash recovery | WAL and recovery |
System catalogs (pg_class, pg_attribute, ...) |
Catalog |
| Streaming and logical replication | Replication |
| The postmaster's startup/fork dance | Postmaster and process model |
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.