commit 5b747b6427c9f5bf080ed61073f9be4eef66d537 Author: David G. Johnston Date: Tue Apr 12 23:08:49 2022 +0000 doc-wip: thoughts regarding reworking of vacuum-transaction-wraparound section diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml index a209a63304..88e1a47cde 100644 --- a/doc/src/sgml/maintenance.sgml +++ b/doc/src/sgml/maintenance.sgml @@ -414,77 +414,32 @@ - PostgreSQL's - MVCC transaction semantics - depend on being able to compare transaction ID (XID) - numbers: a row version with an insertion XID greater than the current - transaction's XID is in the future and should not be visible - to the current transaction. But since transaction IDs have limited size - (32 bits) a cluster that runs for a long time (more - than 4 billion transactions) would suffer transaction ID - wraparound: the XID counter wraps around to zero, and all of a sudden - transactions that were in the past appear to be in the future — which - means their output become invisible. In short, catastrophic data loss. - (Actually the data is still there, but that's cold comfort if you cannot - get at it.) To avoid this, it is necessary to vacuum every table - in every database at least once every two billion transactions. + This vacuum responsibility is necessary due to the fact that transaction ID (xid) numbers + are assigned serially and stored in a unsiged 32bit integer: incrementing INT_MAX causes + a wraparound such that the value becomes INT_MIN. Because of this, the id space is + circular, and the shortest path between two transactions either goes backward or forward, + representing visible and not visible respectively. This results in a situation where, + without maintenance, a transaction (or, more precisely, the rows created by that transaction, + the xid being stored in xmin) that was reached going backward from the current transaction + will have a shorter path going forward for some future transaction. Thus vacuum will + periodically flag older transactions as being "frozen", such that they are considered visible + to every "current" transaction without using the shortest path logic. - + - The reason that periodic vacuuming solves the problem is that - VACUUM will mark rows as frozen, indicating that - they were inserted by a transaction that committed sufficiently far in - the past that the effects of the inserting transaction are certain to be - visible to all current and future transactions. - Normal XIDs are - compared using modulo-232 arithmetic. This means - that for every normal XID, there are two billion XIDs that are - older and two billion that are newer; another - way to say it is that the normal XID space is circular with no - endpoint. Therefore, once a row version has been created with a particular - normal XID, the row version will appear to be in the past for - the next two billion transactions, no matter which normal XID we are - talking about. If the row version still exists after more than two billion - transactions, it will suddenly appear to be in the future. To - prevent this, PostgreSQL reserves a special XID, - FrozenTransactionId, which does not follow the normal XID - comparison rules and is always considered older - than every normal XID. - Frozen row versions are treated as if the inserting XID were - FrozenTransactionId, so that they will appear to be - in the past to all normal transactions regardless of wraparound - issues, and so such row versions will be valid until deleted, no matter - how long that is. + While vacuum will not touch a row's xmin while updating its frozen status, two reserved xid + values may seen. BootstreapTransactionId (1) may be seen on system catalog + tables to indicate records inserted during initdb. FronzenTransactionID (2) + may be seen on any table and also indicates that the row is frozen. This was the mechanism + used in versions prior to 9.4, when it was decided to keep the xmin unchanged for forensic use. - - - In PostgreSQL versions before 9.4, freezing was - implemented by actually replacing a row's insertion XID - with FrozenTransactionId, which was visible in the - row's xmin system column. Newer versions just set a flag - bit, preserving the row's original xmin for possible - forensic use. However, rows with xmin equal - to FrozenTransactionId (2) may still be found - in databases pg_upgrade'd from pre-9.4 versions. - - - Also, system catalogs may contain rows with xmin equal - to BootstrapTransactionId (1), indicating that they were - inserted during the first phase of initdb. - Like FrozenTransactionId, this special XID is treated as - older than every normal XID. - - - - - controls how old an XID value has to be before rows bearing that XID will be - frozen. Increasing this setting may avoid unnecessary work if the - rows that would otherwise be frozen will soon be modified again, - but decreasing this setting increases - the number of transactions that can elapse before the table must be - vacuumed again. + The shortest path mechanism on the circular 32bit space results in a 2 billion transaction + window. While a row can be frozen anytime while in that window doing so too soon will be + wasted effort if the row becomes dead long before it would have left the window. + The setting controls how old a row has to be + before it is eligible for freezing.