agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH v6] README for 64bit xid 265+ messages / 2 participants [nested] [flat]
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v6] README for 64bit xid @ 2022-01-10 19:20 Pavel Borisov <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw) Authors: - Pavel Borisov <[email protected]> - Maxim Orlov <[email protected]> - Yura Sokolov <[email protected]> <[email protected]> --- src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/backend/access/heap/README.XID64 diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64 new file mode 100644 index 00000000000..457ba9b9ef5 --- /dev/null +++ b/src/backend/access/heap/README.XID64 @@ -0,0 +1,128 @@ +src/backend/access/heap/README.XID64 + +64-bit Transaction ID's (XID) +============================= + +A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent +wraparound every N/2 transactions. This causes performance degradation due +to the need to exclusively lock tables while being vacuumed. In each +wraparound cycle, SLRU buffers are also being cut. + +With 64-bit XID's wraparound is effectively postponed to a very distant +future. Even in highly loaded systems that had 2^32 transactions per day +it will take huge 2^31 days before the first enforced "vacuum to prevent +wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA +can plan them independently at the time with the least system load and least +critical for database performance. Also, it can be done less frequently +(several times a year vs every several days) on systems with transaction rates +similar to those mentioned above. + +On-disk tuple and page format +----------------------------- + +On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the +lower parts of 64-bit XMIN and XMAX values. Each heap page has additional +64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page. +They are placed into a pd_special area - 16 bytes in the end of a heap page. +Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page +as follows: + +XMIN = t_xmin + pd_xid_base. (1) +XMAX = t_xmax + pd_xid_base/pd_multi_base. (2) + +"Double XMAX" page format +--------------------------------- + +At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL +version pd_special area with a size of 16 bytes should be added to a page. +Though a page may not have space for this. Then it can be converted to a +temporary format called "double XMAX". + +All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId. +So we don't need tuple header t_xmin field and we reuse t_xmin to store higher +32 bits of its XMAX. + +Double XMAX format is only for full pages that don't have 16 bytes for +pd_special. So it neither has a�place for a single tuple. Insert and HOT update +for double XMAX pages is impossible and not supported. We can only read or +delete tuples from it. + +When we are able to prune page double XMAX it will be converted from it to +general 64-bit XID page format with all operations on its tuples supported. + +In-memory tuple format +---------------------- + +In-memory tuple representation consists of two parts: +- HeapTupleHeader from disk page (contains all heap tuple contents, not only +header) +- HeapTuple with additional in-memory fields + +HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of +page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from +HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX: + +XMIN = t_xmin + t_xid_base. (3) +XMAX = t_xmax + t_xid_base/t_multi_base. (4) + +The downside of this is that we can not use tuple's XMIN and XMAX right away. +We often need to re-read t_xmin and t_xmax - which could actually be pointers +into a page in shared buffers and therefore they could be updated by any other +backend. + +Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax +-------------------------------------------------------------- + +When we try to delete/update a tuple, we check that XMAX for a page fits (2). +I.e. that t_xmax will not be over MaxShortTransactionId relative to +pd_xid_base/pd_multi_base of a its page. + +If the current XID doesn't fit a range +(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5): + +- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on +a page and update all t_xmin/t_xmax of the other tuples on the page to +correspond new pd_xid_base/pd_multi_base. + +- If it was impossible, it will try to prune and freeze tuples on a page. + +- If this is unsuccessful it will throw an error. Normally this is very +unlikely but if there is a very old living transaction with an age of around +2^32 this can arise. Basically, this is a behavior similar to one during the +vacuum to prevent wraparound when XID was 32-bit. Dba should take care and +avoid very-long-living transactions with an age close to 2^32. So long-living +transactions often they are most likely defunct. + +Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax +------------------------------------------------ + +On insert we check if current XID fits a range (5). Otherwise: + +- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will +not be over MaxShortTransactionId. + +- If it is impossible, then it will try to prune and freeze tuples on a page. + +Known issue: if pd_xid_base could not be shifted to accommodate a tuple being +inserted due to a very long-running transaction, we just throw an error. We +neither try to insert a�tuple into another page nor mark the current page as +full. So, in this (unlikely) case we will get regular insert errors on the next +tries to insert to the page 'locked' by this very long-running transaction. + +Upgrade from 32-bit XID versions +-------------------------------- + +pg_upgrade doesn't change pages format itself. It is done lazily after. + +1. At first heap page read, tuples on a page are repacked to free 16 bytes +at the end of a page, possibly freeing space from dead tuples. + +2A. 16 bytes of pd_special is added if there is a place for it + +2B. Page is converted to "Double XMAX" format if there is no place for +pd_special + +3. If a page is in double XMAX format after its first read, and vacuum (or +micro-vacuum at select query) could prune some tuples and free space for +pd_special, prune_page will add pd_special and convert page from double XMAX +to general 64-bit XID page format. -- 2.24.3 (Apple Git-128) --cpok4wp6gsarlzvp-- ^ permalink raw reply [nested|flat] 265+ messages in thread
* [PATCH v16 4/8] Row pattern recognition patch (planner). @ 2024-04-12 06:49 Tatsuo Ishii <[email protected]> 0 siblings, 0 replies; 265+ messages in thread From: Tatsuo Ishii @ 2024-04-12 06:49 UTC (permalink / raw) --- src/backend/optimizer/plan/createplan.c | 24 +++++++++++++++----- src/backend/optimizer/plan/planner.c | 3 +++ src/backend/optimizer/plan/setrefs.c | 27 ++++++++++++++++++++++- src/backend/optimizer/prep/prepjointree.c | 4 ++++ src/include/nodes/plannodes.h | 19 ++++++++++++++++ 5 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 3b77886567..c8d96be7d7 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -287,9 +287,11 @@ static WindowAgg *make_windowagg(List *tlist, Index winref, int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, Oid *ordCollations, int frameOptions, Node *startOffset, Node *endOffset, Oid startInRangeFunc, Oid endInRangeFunc, - Oid inRangeColl, bool inRangeAsc, bool inRangeNullsFirst, - List *runCondition, List *qual, bool topWindow, - Plan *lefttree); + Oid inRangeColl, bool inRangeAsc, bool inRangeNullsFirst, List *runCondition, + RPSkipTo rpSkipTo, List *patternVariable, List *patternRegexp, + List *defineClause, + List *defineInitial, + List *qual, bool topWindow, Plan *lefttree); static Group *make_group(List *tlist, List *qual, int numGroupCols, AttrNumber *grpColIdx, Oid *grpOperators, Oid *grpCollations, Plan *lefttree); @@ -2700,6 +2702,11 @@ create_windowagg_plan(PlannerInfo *root, WindowAggPath *best_path) wc->inRangeAsc, wc->inRangeNullsFirst, wc->runCondition, + wc->rpSkipTo, + wc->patternVariable, + wc->patternRegexp, + wc->defineClause, + wc->defineInitial, best_path->qual, best_path->topwindow, subplan); @@ -6629,8 +6636,10 @@ make_windowagg(List *tlist, Index winref, int ordNumCols, AttrNumber *ordColIdx, Oid *ordOperators, Oid *ordCollations, int frameOptions, Node *startOffset, Node *endOffset, Oid startInRangeFunc, Oid endInRangeFunc, - Oid inRangeColl, bool inRangeAsc, bool inRangeNullsFirst, - List *runCondition, List *qual, bool topWindow, Plan *lefttree) + Oid inRangeColl, bool inRangeAsc, bool inRangeNullsFirst, List *runCondition, + RPSkipTo rpSkipTo, List *patternVariable, List *patternRegexp, List *defineClause, + List *defineInitial, + List *qual, bool topWindow, Plan *lefttree) { WindowAgg *node = makeNode(WindowAgg); Plan *plan = &node->plan; @@ -6656,6 +6665,11 @@ make_windowagg(List *tlist, Index winref, node->inRangeAsc = inRangeAsc; node->inRangeNullsFirst = inRangeNullsFirst; node->topWindow = topWindow; + node->rpSkipTo = rpSkipTo, + node->patternVariable = patternVariable; + node->patternRegexp = patternRegexp; + node->defineClause = defineClause; + node->defineInitial = defineInitial; plan->targetlist = tlist; plan->lefttree = lefttree; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 5320da51a0..5eb66c709b 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -873,6 +873,9 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, wc->runCondition = (List *) preprocess_expression(root, (Node *) wc->runCondition, EXPRKIND_TARGET); + wc->defineClause = (List *) preprocess_expression(root, + (Node *) wc->defineClause, + EXPRKIND_TARGET); } parse->limitOffset = preprocess_expression(root, parse->limitOffset, diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 37abcb4701..cd0e7c57d8 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -210,7 +210,6 @@ static List *set_windowagg_runcondition_references(PlannerInfo *root, List *runcondition, Plan *plan); - /***************************************************************************** * * SUBPLAN REFERENCES @@ -2471,6 +2470,32 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset) NRM_EQUAL, NUM_EXEC_QUAL(plan)); + /* + * Modifies an expression tree in each DEFINE clause so that all Var + * nodes's varno refers to OUTER_VAR. + */ + if (IsA(plan, WindowAgg)) + { + WindowAgg *wplan = (WindowAgg *) plan; + + if (wplan->defineClause != NIL) + { + foreach(l, wplan->defineClause) + { + TargetEntry *tle = (TargetEntry *) lfirst(l); + + tle->expr = (Expr *) + fix_upper_expr(root, + (Node *) tle->expr, + subplan_itlist, + OUTER_VAR, + rtoffset, + NRM_EQUAL, + NUM_EXEC_QUAL(plan)); + } + } + } + pfree(subplan_itlist); } diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 4badb6ff58..1c34360c7c 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -2178,6 +2178,10 @@ perform_pullup_replace_vars(PlannerInfo *root, if (wc->runCondition != NIL) wc->runCondition = (List *) pullup_replace_vars((Node *) wc->runCondition, rvcontext); + + if (wc->defineClause != NIL) + wc->defineClause = (List *) + pullup_replace_vars((Node *) wc->defineClause, rvcontext); } if (parse->onConflict) { diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index e025679f89..90441f4d90 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -20,6 +20,7 @@ #include "lib/stringinfo.h" #include "nodes/bitmapset.h" #include "nodes/lockoptions.h" +#include "nodes/parsenodes.h" #include "nodes/primnodes.h" @@ -1098,6 +1099,24 @@ typedef struct WindowAgg /* nulls sort first for in_range tests? */ bool inRangeNullsFirst; + /* Row Pattern Recognition AFTER MACH SKIP clause */ + RPSkipTo rpSkipTo; /* Row Pattern Skip To type */ + + /* Row Pattern PATTERN variable name (list of String) */ + List *patternVariable; + + /* + * Row Pattern RPATTERN regular expression quantifier ('+' or ''. list of + * String) + */ + List *patternRegexp; + + /* Row Pattern DEFINE clause (list of TargetEntry) */ + List *defineClause; + + /* Row Pattern DEFINE variable initial names (list of String) */ + List *defineInitial; + /* * false for all apart from the WindowAgg that's closest to the root of * the plan -- 2.25.1 ----Next_Part(Fri_Apr_12_16_09_08_2024_262)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v16-0005-Row-pattern-recognition-patch-executor.patch" ^ permalink raw reply [nested|flat] 265+ messages in thread
end of thread, other threads:[~2024-04-12 06:49 UTC | newest] Thread overview: 265+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]> 2024-04-12 06:49 [PATCH v16 4/8] Row pattern recognition patch (planner). Tatsuo Ishii <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox