agora inbox for [email protected]  
help / color / mirror / Atom feed
Duplicate table names
269+ messages / 4 participants
[nested] [flat]

* Duplicate table names
@ 2000-02-06 17:29  Thomas Lockhart <[email protected]>
  0 siblings, 3 replies; 269+ messages in thread

From: Thomas Lockhart @ 2000-02-06 17:29 UTC (permalink / raw)
  To: Postgres Hackers List <[email protected]>

The following query is rejected (and always has been afaik):

select * from t1, t1;

Does this rejection have any basis in SQL92? (I haven't looked; hoping
someone else has.)

istm that

select x from t1, t1;

would have trouble, but the wildcard could do the Right Thing even
without resorting to (for example)

select * from t1 a, t1;

as is currently required. I'm not sure what it would take to do this,
but it probably touches on an area of "outer join syntax" I'm looking
at:

select a, b from t1 join t2 using (a);

is legal, but the "join table" (t1 join t2 using...) must lose its
underlying table names (yuck, only for the join columns), resulting in
disallowing, for example,

select t1.a from t1 join t2 using (a);

That is, the "relation.column" syntax is not allowed to refer to the
join column(s), unless one specifies an alias for the "join table", as
in

select tx.a from (t1 join t2 using (a)) as tx;

I'm thinking of implementing this by allowing multiple RTEs to have
the *same* table alias, (as long as there aren't column name conflicts
in the "visible" columns), so that, at least internally,

select * from t1 tx, t3 tx;

becomes legal as long as t1 and t3 do not share common column names.

Comments on either or both issues?

                     - Thomas

-- 
Thomas Lockhart				[email protected]
South Pasadena, California



^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* Re: [HACKERS] Duplicate table names
@ 2000-02-07 19:49  Peter Eisentraut <[email protected]>
  parent: Thomas Lockhart <[email protected]>
  2 siblings, 0 replies; 269+ messages in thread

From: Peter Eisentraut @ 2000-02-07 19:49 UTC (permalink / raw)
  To: Thomas Lockhart <[email protected]>; +Cc: Postgres Hackers List <[email protected]>

On 2000-02-06, Thomas Lockhart mentioned:

> The following query is rejected (and always has been afaik):
> 
> select * from t1, t1;
> 
> Does this rejection have any basis in SQL92? (I haven't looked; hoping
> someone else has.)

Not according to the way I decoded it. It's a join of t1 with itself and
you get all columns twice.

> 
> istm that
> 
> select x from t1, t1;
> 
> would have trouble, but the wildcard could do the Right Thing even

This is the same problem as

select x from t1, t2;

where both t1 and t2 have a column x. It's an error. It's not an error if
column x is unambiguous. Chances are pretty good (=100%) that there will
be ambiguity if you list the same table twice, but there's no reason to
reject this for the reason it gives now.

[snip]
> I'm thinking of implementing this by allowing multiple RTEs to have
> the *same* table alias, (as long as there aren't column name conflicts
> in the "visible" columns), so that, at least internally,
> 
> select * from t1 tx, t3 tx;
> 
> becomes legal as long as t1 and t3 do not share common column names.

This seems perfectly legal as well, even if they do share column names.
Any reference to tx.y will fail due to ambiguity, but it shouldn't merely
because of name checking.

-- 
Peter Eisentraut                  Sernanders väg 10:115
[email protected]                   75262 Uppsala
http://yi.org/peter-e/            Sweden




^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* Re: [HACKERS] Duplicate table names
@ 2000-02-07 20:26  Don Baccus <[email protected]>
  parent: Thomas Lockhart <[email protected]>
  2 siblings, 1 reply; 269+ messages in thread

From: Don Baccus @ 2000-02-07 20:26 UTC (permalink / raw)
  To: Peter Eisentraut <[email protected]>; Thomas Lockhart <[email protected]>; +Cc: Postgres Hackers List <[email protected]>

At 08:49 PM 2/7/00 +0100, Peter Eisentraut wrote:

>Not according to the way I decoded it. It's a join of t1 with itself and
>you get all columns twice.

...

>This is the same problem as
>
>select x from t1, t2;
>
>where both t1 and t2 have a column x. It's an error. It's not an error if
>column x is unambiguous. Chances are pretty good (=100%) that there will
>be ambiguity if you list the same table twice, but there's no reason to
>reject this for the reason it gives now.

I believe that Peter's right on all counts.

>
>[snip]
>> I'm thinking of implementing this by allowing multiple RTEs to have
>> the *same* table alias, (as long as there aren't column name conflicts
>> in the "visible" columns), so that, at least internally,
>> 
>> select * from t1 tx, t3 tx;

>> becomes legal as long as t1 and t3 do not share common column names.

>This seems perfectly legal as well, even if they do share column names.
>Any reference to tx.y will fail due to ambiguity, but it shouldn't merely
>because of name checking.

Actually, according to Date an explicit range variable must be
unique within a given scope.

Does Postgres implement scope?  Apparently JOIN opens a new
scope...so do subselects.

select * from t1 tx, t3 tx is not legal SQL

select * from t1 tx, (select * from t3 tx) is legal SQL.

The tx inside the subselect hides the outer tx, just like
any 'ole block-structured language.

Date takes over six pages of fairly terse prose with few examples to
define the scope of range variables in and out of JOIN expressions.
A bit over one page of that is devoted to scoping issues unique
to JOINs, which I don't feel like reading at the moment!




- Don Baccus, Portland OR <[email protected]>
  Nature photos, on-line guides, Pacific Northwest
  Rare Bird Alert Service and other goodies at
  http://donb.photo.net.



^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* Re: [HACKERS] Duplicate table names
@ 2000-02-07 21:03  Don Baccus <[email protected]>
  parent: Thomas Lockhart <[email protected]>
  2 siblings, 0 replies; 269+ messages in thread

From: Don Baccus @ 2000-02-07 21:03 UTC (permalink / raw)
  To: Peter Eisentraut <[email protected]>; Thomas Lockhart <[email protected]>; +Cc: Postgres Hackers List <[email protected]>

At 12:26 PM 2/7/00 -0800, Don Baccus wrote:

>>> select * from t1 tx, t3 tx;

>>> becomes legal as long as t1 and t3 do not share common column names.

>>This seems perfectly legal as well, even if they do share column names.
>>Any reference to tx.y will fail due to ambiguity, but it shouldn't merely
>>because of name checking.

>Actually, according to Date an explicit range variable must be
>unique within a given scope.

I consulted the Oracle, and it agrees with Peter, hmmm...and the
wording in Date's a bit ambiguous, he's not clear as to whether
the range variable must be unique when DEFINED, or must only be
unique if it is referenced, i.e. select tx.foo from t1 tx, t3 tx
is ambiguous.

Reading further into Date, he says that

select ... from t1 

implicitly defines t1 as a range variable, and since

select ... from t1, t1 is legal, then range variables need not be
unique to be defined, 'cause according to the standard this
causes two range variables named t1 to be implicitly defined.

So, his comment about uniqueness within scope applies to whether
or not you can explicitly REFERENCE, not DEFINE the range var.

Sorry for the confusion...Peter was right all along.




- Don Baccus, Portland OR <[email protected]>
  Nature photos, on-line guides, Pacific Northwest
  Rare Bird Alert Service and other goodies at
  http://donb.photo.net.



^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* Re: [HACKERS] Duplicate table names
@ 2000-02-08 06:54  Thomas Lockhart <[email protected]>
  parent: Don Baccus <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Thomas Lockhart @ 2000-02-08 06:54 UTC (permalink / raw)
  To: Don Baccus <[email protected]>; +Cc: Peter Eisentraut <[email protected]>; Postgres Hackers List <[email protected]>

> Date takes over six pages of fairly terse prose with few examples to
> define the scope of range variables in and out of JOIN expressions.
> A bit over one page of that is devoted to scoping issues unique
> to JOINs, which I don't feel like reading at the moment!

Right. We're not likely to meet all of the scoping rules in the first
implementation; they are *really* tough :(

                     - Thomas

-- 
Thomas Lockhart				[email protected]
South Pasadena, California



^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 269+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 269+ messages in thread


end of thread, other threads:[~2022-01-10 19:20 UTC | newest]

Thread overview: 269+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2000-02-06 17:29 Duplicate table names Thomas Lockhart <[email protected]>
2000-02-07 19:49 ` Peter Eisentraut <[email protected]>
2000-02-07 20:26 ` Don Baccus <[email protected]>
2000-02-08 06:54   ` Thomas Lockhart <[email protected]>
2000-02-07 21:03 ` Don Baccus <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[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