Skip to content

PostgreSQL Server Architecture — Section Overview

Contents:

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:

  1. The fork model and backend lifecycle — the single postmaster, its child_process_kinds registry, the fork() (or EXEC_BACKEND re-exec) path, and what a client backend does from InitProcess through InitPostgres to the PostgresMain message loop.
  2. The shared-memory / IPC substrate — how the fixed segment is sized once and created at boot (CalculateShmemSizeCreateSharedMemoryAndSemaphores), the PGPROC/ProcGlobal slots that back every process, and the dynamic layer (dsm, dsa, shm_mq) that parallel query and extensions use after boot.
  3. The three lock layers. This is the section’s center of gravity, and it is structured exactly as storage/lmgr/README enumerates 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/PROCLOCK hash, AccessShareLockAccessExclusiveLock) with a full waits-for deadlock detector.
    • SSI predicate locksSIReadLocks and the Serializable Snapshot Isolation machinery that makes SERIALIZABLE work without blocking readers.
  4. Latches and signals — the wakeup fabric: SetLatch/WaitLatch, the WaitEventSet multiplexer, procsignal, and the interrupt handlers that turn signals into safely-deferred actions.
  5. 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 RegisterBackgroundWorker API 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 in txn-recovery. SSI is documented here as a locking mechanism; its isolation semantics connect to the snapshot model in txn-recovery.
  • Down to storage-engine. LWLocks protect buffer headers and the buffer pool, but the buffer manager and its WAL-before-flush rule are storage-engine material. 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 uses shm_mq and background workers from this section, but the pipeline itself and the Gather/execParallel machinery are query-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 as BackendType inhabitants and points onward.
  • Cache invalidation (sinval) rides the same shared-memory substrate but is owned by system-catalog (postgres-cache-invalidation.md); this section only notes that the queue lives in the segment sized here.

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.

Figure 1 — The server-architecture substrate: postmaster, children, shared memory, locks, latches

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.

Cross-referenced-first: read the substrate before the things that stand on it, and the lock primitives before the lock policy.

  1. postgres-shared-memory-ipc.md — the foundation. The segment, the PGPROC/ProcGlobal slots, and the dynamic dsm/dsa/shm_mq layer are referenced by everything else in this section.
  2. postgres-postmaster.md — who creates the segment and who forks the inhabitants; the BackendType / child_process_kinds registry.
  3. postgres-backend-lifecycle.md — what a forked client backend actually does (InitProcessInitPostgres → message loop), so the later mechanisms have a concrete owner.
  4. postgres-lwlock-spinlock.md — the lock primitive, read before the layers built on top of it.
  5. postgres-lock-manager.md — the heavyweight table and the deadlock detector; depends on the LWLock primitive and the PGPROC wait queue.
  6. postgres-ssi-predicate-locking.md — predicate locking and SSI; read after the heavyweight manager since it reuses the lmgr framing, and alongside the txn-recovery snapshot docs for the isolation half.
  7. postgres-latch-signals.md — the wakeup fabric that the lock waits and the aux processes block on.
  8. postgres-aux-processes.md then postgres-background-workers.md — the remaining inhabitants, last because they consume all of the above.

Forward references — these module docs may not exist yet; the descriptions are the planned scope of each.

Module docOne-line scope
postgres-postmaster.mdThe single fork parent: PostmasterMainServerLoop, 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.mdThe 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.mdThe IPC substrate: sizing the fixed segment (CalculateShmemSizeCreateSharedMemoryAndSemaphores), 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.mdThe 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.mdThe 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.mdSerializable 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.mdThe 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.mdThe 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.mdThe 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.
Section overviewWhy it borders this one
postgres-overview-txn-recovery.mdThe 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.mdLWLocks 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.mdA 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.mdThe 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.mdwalsender/walreceiver and the slot-sync worker are BackendType inhabitants forked by the postmaster; their replication behavior is owned there.
postgres-overview-monitoring-stats.mdThe 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.