Inside PostgreSQL: How Its Three‑Layer Transaction Model Works
PostgreSQL implements transactions through a three‑layer architecture—top, middle, and bottom—where the top layer handles user‑visible commands, the middle layer processes statement‑level actions, and the bottom layer manages low‑level atomic operations, each with specific functions and state handling.
Top Layer
The top layer is user‑controlled and visible; it defines the transaction boundaries that users start and end with commands such as BEGIN, COMMIT, ROLLBACK, SAVEPOINT, ROLLBACK TO, and RELEASE. The PostgreSQL traffic cop forwards these calls to the corresponding top‑layer routines:
BeginTransactionBlock
EndTransactionBlock
UserAbortTransactionBlock
DefineSavepoint
RollbackToSavepoint
ReleaseSavepoint
Middle Layer
The middle layer operates at the statement level and is invisible to the user. It wraps each SQL statement with specific functions defined in postgres.c:
StartTransactionCommand
CommitTransactionCommand
AbortCurrentTransaction
Bottom Layer
The bottom layer implements the actual atomic transaction mechanics at the row level, including nested transaction handling. Its functions are:
StartTransaction
CommitTransaction
AbortTransaction
CleanupTransaction
StartSubTransaction
CommitSubTransaction
AbortSubTransaction
CleanupSubTransaction
Execution Flow Example
Consider the following SQL sequence:
1) BEGIN
2) SELECT * FROM foo
3) INSERT INTO foo VALUES (...)
4) COMMITThe corresponding internal calls proceed as:
/ StartTransactionCommand;
/ StartTransaction;
1) < ProcessUtility << BEGIN
\ BeginTransactionBlock;
\ CommitTransactionCommand; / StartTransactionCommand;
2) / ProcessQuery << SELECT ...
\ CommitTransactionCommand;
\ CommandCounterIncrement; / StartTransactionCommand;
3) / ProcessQuery << INSERT ...
\ CommitTransactionCommand;
\ CommandCounterIncrement; / StartTransactionCommand;
/ ProcessUtility << COMMIT
4) < EndTransactionBlock;
\ CommitTransactionCommand;
\ CommitTransaction;During BEGIN, the top‑layer forwards the request to BeginTransactionBlock, which sets the transaction block state to TBLOCK_START. The middle layer then invokes StartTransaction in the bottom layer, creating a virtual transaction ID (vxid) and initializing transaction state ( TRANS_INPROCESS), isolation level, read‑only flag, and recovery status.
Each SELECT and INSERT is wrapped by the middle layer’s ProcessQuery (or ProcessUtility) functions, which also assign a command ID (CID) for MVCC visibility checks. For DML statements, the bottom layer assigns a transaction ID to the tuple header ( xmin / xmax) and updates the command ID, ensuring proper visibility.
When COMMIT is issued, both the top‑layer transaction block and the low‑level transaction are closed, guaranteeing atomicity, releasing buffers, locks, and other resources.
ACID Guarantees in PostgreSQL
Atomicity is provided by the bottom layer, starting with StartTransaction and ending with CommitTransaction.
Consistency is enforced at the statement level (middle layer) and by updating tuple headers ( xmin, xmax, cmin, cmax) for MVCC visibility.
Isolation is set during StartTransaction, establishing the transaction’s isolation level and snapshot for MVCC.
Durability is achieved through CommitTransaction, which writes to the Write‑Ahead Log (WAL) to ensure data can be recovered after a crash.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
