PostgreSQL Server Architecture — Section Overview
Contents:
What this section covers
Section titled “What this section covers”This subcategory is the machine itself — the processes and the coordination fabric they share — as distinct from the work those processes do. The architecture overview’s thesis is that in PostgreSQL the shared memory is the architecture and the processes are interchangeable inhabitants of it; this section documents both halves of that sentence at the mechanism level: who the inhabitants are, and how they attach, coordinate, lock, and signal.
Concretely, the scope is five clusters:
- The fork model and backend lifecycle — the single postmaster, its
child_process_kindsregistry, thefork()(orEXEC_BACKENDre-exec) path, and what a client backend does fromInitProcessthroughInitPostgresto thePostgresMainmessage loop. - The shared-memory / IPC substrate — how the fixed segment is sized
once and created at boot (
CalculateShmemSize→CreateSharedMemoryAndSemaphores), thePGPROC/ProcGlobalslots that back every process, and the dynamic layer (dsm,dsa,shm_mq) that parallel query and extensions use after boot. - The three lock layers. This is the section’s center of gravity, and
it is structured exactly as
storage/lmgr/READMEenumerates them:- LWLocks + spinlocks — short, two-mode (shared/exclusive) latches that protect in-memory shared structures; no deadlock detection, not SQL-visible.
- The heavyweight (regular) lock table — the SQL-level lock manager
(
LOCK/PROCLOCKhash,AccessShareLock…AccessExclusiveLock) with a full waits-for deadlock detector. - SSI predicate locks —
SIReadLocks and the Serializable Snapshot Isolation machinery that makesSERIALIZABLEwork without blocking readers.
- Latches and signals — the wakeup fabric:
SetLatch/WaitLatch, theWaitEventSetmultiplexer,procsignal, and the interrupt handlers that turn signals into safely-deferred actions. - The auxiliary processes and the background-worker framework — the
non-client inhabitants (startup, checkpointer, bgwriter, walwriter,
syslogger, plus the PG18 I/O workers) and the
RegisterBackgroundWorkerAPI that lets parallel query, logical-apply, and extensions spawn more.
Sharp boundaries — what this section is NOT. This subcategory owns the coordination primitives and the process container, and defers every payload subsystem to a neighbor:
- Down to
txn-recovery. The lock layers here are the locking machinery; the transactional meaning of locks — snapshots, the procarray that lock waits consult, WAL, commit/abort, recovery — lives intxn-recovery. SSI is documented here as a locking mechanism; its isolation semantics connect to the snapshot model intxn-recovery. - Down to
storage-engine. LWLocks protect buffer headers and the buffer pool, but the buffer manager and its WAL-before-flush rule arestorage-enginematerial. This section stops at “LWLocks are the primitive”; what they protect is described where the protected structure lives. - Across to
query-processing. A backend runs the parse→plan→execute pipeline, and parallel query usesshm_mqand background workers from this section, but the pipeline itself and theGather/execParallelmachinery arequery-processing. - Across to
replication-ha,monitoring-stats,ddl-schema.walsender/walreceiver,autovacuum, the cumulative-stats subsystem, and DDL are all roles the postmaster forks or consumers of the sinval queue, but their behavior is owned by those sections. This router names them asBackendTypeinhabitants and points onward. - Cache invalidation (
sinval) rides the same shared-memory substrate but is owned bysystem-catalog(postgres-cache-invalidation.md); this section only notes that the queue lives in the segment sized here.
The substrate
Section titled “The substrate”The diagram shows how the module docs in this subcategory relate: the
postmaster sizes and creates the shared segment, forks the inhabitants, and
those inhabitants coordinate through the IPC substrate, the three lock
layers, and the latch/signal fabric. Node labels name the
postgres-*.md docs.
Two structural facts a reader should carry out of this diagram. First, the
lock layers are not a hierarchy of strength but three different
subsystems with different jobs — the README is emphatic that LWLocks,
heavyweight locks, and predicate locks are distinct mechanisms; only the
heavyweight layer has deadlock detection, and only SSI implements predicate
locking. Second, everything here is mediated by PGPROC: a backend’s
heavyweight-lock wait queue, its latch, and its proc-signal slot all hang
off its PGPROC entry, which is why proc.c shows up in both the
lock-manager and the shared-memory-ipc docs.
Reading order
Section titled “Reading order”Cross-referenced-first: read the substrate before the things that stand on it, and the lock primitives before the lock policy.
postgres-shared-memory-ipc.md— the foundation. The segment, thePGPROC/ProcGlobalslots, and the dynamic dsm/dsa/shm_mq layer are referenced by everything else in this section.postgres-postmaster.md— who creates the segment and who forks the inhabitants; theBackendType/child_process_kindsregistry.postgres-backend-lifecycle.md— what a forked client backend actually does (InitProcess→InitPostgres→ message loop), so the later mechanisms have a concrete owner.postgres-lwlock-spinlock.md— the lock primitive, read before the layers built on top of it.postgres-lock-manager.md— the heavyweight table and the deadlock detector; depends on the LWLock primitive and thePGPROCwait queue.postgres-ssi-predicate-locking.md— predicate locking and SSI; read after the heavyweight manager since it reuses thelmgrframing, and alongside thetxn-recoverysnapshot docs for the isolation half.postgres-latch-signals.md— the wakeup fabric that the lock waits and the aux processes block on.postgres-aux-processes.mdthenpostgres-background-workers.md— the remaining inhabitants, last because they consume all of the above.
Detail-doc summaries
Section titled “Detail-doc summaries”Forward references — these module docs may not exist yet; the descriptions are the planned scope of each.
| Module doc | One-line scope |
|---|---|
postgres-postmaster.md | The single fork parent: PostmasterMain → ServerLoop, the child_process_kinds registry and BackendType roles, postmaster_child_launch (fork_process vs EXEC_BACKEND re-exec), and crash/restart supervision. |
postgres-backend-lifecycle.md | The life of a client backend from fork to exit: InitProcess (claim a PGPROC), InitPostgres (attach DB, build caches), the PostgresMain read-parse-execute message loop, and teardown via resource owners and on-shmem-exit callbacks. |
postgres-shared-memory-ipc.md | The IPC substrate: sizing the fixed segment (CalculateShmemSize → CreateSharedMemoryAndSemaphores), ShmemAlloc/ShmemInitStruct, the PGPROC/ProcGlobal slot pool, and the dynamic layer — dsm segments, the dsa allocator, and the shm_mq single-reader/writer queue used by parallel workers. |
postgres-lock-manager.md | The heavyweight (regular) lock manager: the LOCK/PROCLOCK shared hash partitioned by lock tag, lock modes and the conflict table, fast-path locking, LockAcquire/LockRelease, the PGPROC wait queue, and the DeadLockCheck waits-for cycle detector. |
postgres-lwlock-spinlock.md | The lightweight layer: spinlocks and port/atomics as the hardware base, LWLockAcquire/LWLockRelease, shared vs exclusive modes, tranches and named LWLocks, and why this layer has no deadlock detection or SQL visibility. |
postgres-ssi-predicate-locking.md | Serializable Snapshot Isolation: SIReadLock predicate locks at multiple granularities, rw-conflict tracking (SerializableXact), the dangerous-structure detection that aborts one transaction to preserve serializability, and the predicate.c / README-SSI design. |
postgres-latch-signals.md | The wakeup fabric: Latch and SetLatch/WaitLatch, the WaitEventSet multiplexer over sockets/latches/signals, ProcSignal cross-backend signaling, and the interrupt pattern (ProcessInterrupts, deferred CHECK_FOR_INTERRUPTS). |
postgres-background-workers.md | The bgworker framework: RegisterBackgroundWorker (static) vs RegisterDynamicBackgroundWorker, BackgroundWorkerInitializeConnection, the postmaster slot lifecycle, and how parallel query and logical-replication apply build on it via dsm/shm_mq. |
postgres-aux-processes.md | The fixed auxiliary processes: startup (recovery driver), checkpointer, bgwriter, walwriter, syslogger, and the PG18 I/O workers — each entered via AuxiliaryProcessMainCommon, what each services, and which shared structures it owns. |
Adjacent sections
Section titled “Adjacent sections”| Section overview | Why it borders this one |
|---|---|
postgres-overview-txn-recovery.md | The deepest seam. The lock layers here are mechanism; their transactional meaning — snapshots (the procarray that lock waits consult), WAL, commit/abort, recovery — lives there. SSI’s isolation semantics connect to its snapshot model. |
postgres-overview-storage-engine.md | LWLocks protect buffer headers and the shared buffer pool; the buffer manager, smgr, and the WAL-before-flush rule are owned there. This section provides the lock primitive; that one provides the protected structures. |
postgres-overview-query-processing.md | A backend (lifecycle doc) runs the query pipeline; parallel query consumes shm_mq and background workers from this section. The Gather/execParallel machinery itself is owned there. |
postgres-overview-system-catalog.md | The sinval cache-invalidation queue rides the shared-memory substrate sized here, but the invalidation loop and relcache/catcache are owned by postgres-cache-invalidation.md. |
postgres-overview-replication-ha.md | walsender/walreceiver and the slot-sync worker are BackendType inhabitants forked by the postmaster; their replication behavior is owned there. |
postgres-overview-monitoring-stats.md | The cumulative-stats subsystem lives in shared memory and is drained by backends, but wait-event reporting (which names the very LWLocks/heavyweight waits defined here) is owned there. |