agora inbox for [email protected]  
help / color / mirror / Atom feed
Simplify passing of configure arguments to pg_config
268+ messages / 3 participants
[nested] [flat]

* Simplify passing of configure arguments to pg_config
@ 2019-12-02 12:27  Peter Eisentraut <[email protected]>
  0 siblings, 1 reply; 268+ messages in thread

From: Peter Eisentraut @ 2019-12-02 12:27 UTC (permalink / raw)
  To: pgsql-hackers

Currently, configure puts the configure args into the makefiles and
then have the makefiles pass them to the build of pg_config.  That looks 
like an unnecessary redirection, and indeed that method was
put in place when pg_config was a shell script.  We can simplify that
by having configure put the value into pg_config.h directly.  This
also makes the standard build system match how the MSVC build system
already does it.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

From 8edb9c20cbee740b5d2acb3c68f0a3f8231fb3dc Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Mon, 2 Dec 2019 13:16:39 +0100
Subject: [PATCH] Simplify passing of configure arguments to pg_config

The previous system had configure put the value into the makefiles and
then have the makefiles pass them to the build of pg_config.  That was
put in place when pg_config was a shell script.  We can simplify that
by having configure put the value into pg_config.h directly.  This
also makes the standard build system match how the MSVC build system
already does it.
---
 configure                  | 8 ++++++--
 configure.in               | 4 +++-
 src/Makefile.global.in     | 3 ---
 src/common/Makefile        | 1 -
 src/common/config_info.c   | 6 +-----
 src/include/pg_config.h.in | 3 +++
 src/tools/msvc/Solution.pm | 2 +-
 7 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/configure b/configure
index 1d88983b34..5cbe8e91d8 100755
--- a/configure
+++ b/configure
@@ -776,7 +776,6 @@ build_vendor
 build_cpu
 build
 PG_MAJORVERSION
-configure_args
 target_alias
 host_alias
 build_alias
@@ -2797,7 +2796,12 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 
 
-configure_args=$ac_configure_args
+
+ac_configure_args_escaped=`$as_echo "$ac_configure_args" | sed 's/"/\\\\"/g'`
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIGURE_ARGS "$ac_configure_args_escaped"
+_ACEOF
 
 
 PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`
diff --git a/configure.in b/configure.in
index a2cb20b5e3..4f2427720c 100644
--- a/configure.in
+++ b/configure.in
@@ -27,7 +27,9 @@ AC_COPYRIGHT([Copyright (c) 1996-2019, PostgreSQL Global Development Group])
 AC_CONFIG_SRCDIR([src/backend/access/common/heaptuple.c])
 AC_CONFIG_AUX_DIR(config)
 AC_PREFIX_DEFAULT(/usr/local/pgsql)
-AC_SUBST(configure_args, [$ac_configure_args])
+
+ac_configure_args_escaped=`$as_echo "$ac_configure_args" | sed 's/"/\\\\"/g'`
+AC_DEFINE_UNQUOTED(CONFIGURE_ARGS, ["$ac_configure_args_escaped"], [Arguments passed to configure])
 
 [PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`]
 AC_SUBST(PG_MAJORVERSION)
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 05b66380e0..95f5a104e5 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -74,9 +74,6 @@ endif # not PGXS
 
 vpathsearch = `for f in $(addsuffix /$(1),$(subst :, ,. $(VPATH))); do test -r $$f && echo $$f && break; done`
 
-# Saved arguments from configure
-configure_args = @configure_args@
-
 
 ##########################################################################
 #
diff --git a/src/common/Makefile b/src/common/Makefile
index ffb0f6edff..fd43558830 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -31,7 +31,6 @@ include $(top_builddir)/src/Makefile.global
 # don't include subdirectory-path-dependent -I and -L switches
 STD_CPPFLAGS := $(filter-out -I$(top_srcdir)/src/include -I$(top_builddir)/src/include,$(CPPFLAGS))
 STD_LDFLAGS := $(filter-out -L$(top_builddir)/src/common -L$(top_builddir)/src/port,$(LDFLAGS))
-override CPPFLAGS += -DVAL_CONFIGURE="\"$(configure_args)\""
 override CPPFLAGS += -DVAL_CC="\"$(CC)\""
 override CPPFLAGS += -DVAL_CPPFLAGS="\"$(STD_CPPFLAGS)\""
 override CPPFLAGS += -DVAL_CFLAGS="\"$(CFLAGS)\""
diff --git a/src/common/config_info.c b/src/common/config_info.c
index dd34fbfc00..902f8226a4 100644
--- a/src/common/config_info.c
+++ b/src/common/config_info.c
@@ -124,11 +124,7 @@ get_configdata(const char *my_exec_path, size_t *configdata_len)
 	i++;
 
 	configdata[i].name = pstrdup("CONFIGURE");
-#ifdef VAL_CONFIGURE
-	configdata[i].setting = pstrdup(VAL_CONFIGURE);
-#else
-	configdata[i].setting = pstrdup(_("not recorded"));
-#endif
+	configdata[i].setting = pstrdup(CONFIGURE_ARGS);
 	i++;
 
 	configdata[i].name = pstrdup("CC");
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index c208dcdfc7..c8384c6c04 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -42,6 +42,9 @@
    Changing BLCKSZ requires an initdb. */
 #undef BLCKSZ
 
+/* Arguments passed to configure */
+#undef CONFIGURE_ARGS
+
 /* Define to the default TCP port number on which the server listens and to
    which clients will try to connect. This can be overridden at run-time, but
    it's convenient if your clients have the right default compiled in.
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 5f72530c72..e9efc97e14 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -247,7 +247,7 @@ sub GenerateFiles
 			print $o "#define DEF_PGPORT $port\n";
 			print $o "#define DEF_PGPORT_STR \"$port\"\n";
 		}
-		print $o "#define VAL_CONFIGURE \""
+		print $o "#define CONFIGURE_ARGS \""
 		  . $self->GetFakeConfigure() . "\"\n";
 		print $o "#endif /* IGNORE_CONFIGURED_SETTINGS */\n";
 		close($o);
-- 
2.24.0



Attachments:

  [text/plain] 0001-Simplify-passing-of-configure-arguments-to-pg_config.patch (4.8K, ../../[email protected]/2-0001-Simplify-passing-of-configure-arguments-to-pg_config.patch)
  download | inline diff:
From 8edb9c20cbee740b5d2acb3c68f0a3f8231fb3dc Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Mon, 2 Dec 2019 13:16:39 +0100
Subject: [PATCH] Simplify passing of configure arguments to pg_config

The previous system had configure put the value into the makefiles and
then have the makefiles pass them to the build of pg_config.  That was
put in place when pg_config was a shell script.  We can simplify that
by having configure put the value into pg_config.h directly.  This
also makes the standard build system match how the MSVC build system
already does it.
---
 configure                  | 8 ++++++--
 configure.in               | 4 +++-
 src/Makefile.global.in     | 3 ---
 src/common/Makefile        | 1 -
 src/common/config_info.c   | 6 +-----
 src/include/pg_config.h.in | 3 +++
 src/tools/msvc/Solution.pm | 2 +-
 7 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/configure b/configure
index 1d88983b34..5cbe8e91d8 100755
--- a/configure
+++ b/configure
@@ -776,7 +776,6 @@ build_vendor
 build_cpu
 build
 PG_MAJORVERSION
-configure_args
 target_alias
 host_alias
 build_alias
@@ -2797,7 +2796,12 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 
 
-configure_args=$ac_configure_args
+
+ac_configure_args_escaped=`$as_echo "$ac_configure_args" | sed 's/"/\\\\"/g'`
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIGURE_ARGS "$ac_configure_args_escaped"
+_ACEOF
 
 
 PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`
diff --git a/configure.in b/configure.in
index a2cb20b5e3..4f2427720c 100644
--- a/configure.in
+++ b/configure.in
@@ -27,7 +27,9 @@ AC_COPYRIGHT([Copyright (c) 1996-2019, PostgreSQL Global Development Group])
 AC_CONFIG_SRCDIR([src/backend/access/common/heaptuple.c])
 AC_CONFIG_AUX_DIR(config)
 AC_PREFIX_DEFAULT(/usr/local/pgsql)
-AC_SUBST(configure_args, [$ac_configure_args])
+
+ac_configure_args_escaped=`$as_echo "$ac_configure_args" | sed 's/"/\\\\"/g'`
+AC_DEFINE_UNQUOTED(CONFIGURE_ARGS, ["$ac_configure_args_escaped"], [Arguments passed to configure])
 
 [PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`]
 AC_SUBST(PG_MAJORVERSION)
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 05b66380e0..95f5a104e5 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -74,9 +74,6 @@ endif # not PGXS
 
 vpathsearch = `for f in $(addsuffix /$(1),$(subst :, ,. $(VPATH))); do test -r $$f && echo $$f && break; done`
 
-# Saved arguments from configure
-configure_args = @configure_args@
-
 
 ##########################################################################
 #
diff --git a/src/common/Makefile b/src/common/Makefile
index ffb0f6edff..fd43558830 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -31,7 +31,6 @@ include $(top_builddir)/src/Makefile.global
 # don't include subdirectory-path-dependent -I and -L switches
 STD_CPPFLAGS := $(filter-out -I$(top_srcdir)/src/include -I$(top_builddir)/src/include,$(CPPFLAGS))
 STD_LDFLAGS := $(filter-out -L$(top_builddir)/src/common -L$(top_builddir)/src/port,$(LDFLAGS))
-override CPPFLAGS += -DVAL_CONFIGURE="\"$(configure_args)\""
 override CPPFLAGS += -DVAL_CC="\"$(CC)\""
 override CPPFLAGS += -DVAL_CPPFLAGS="\"$(STD_CPPFLAGS)\""
 override CPPFLAGS += -DVAL_CFLAGS="\"$(CFLAGS)\""
diff --git a/src/common/config_info.c b/src/common/config_info.c
index dd34fbfc00..902f8226a4 100644
--- a/src/common/config_info.c
+++ b/src/common/config_info.c
@@ -124,11 +124,7 @@ get_configdata(const char *my_exec_path, size_t *configdata_len)
 	i++;
 
 	configdata[i].name = pstrdup("CONFIGURE");
-#ifdef VAL_CONFIGURE
-	configdata[i].setting = pstrdup(VAL_CONFIGURE);
-#else
-	configdata[i].setting = pstrdup(_("not recorded"));
-#endif
+	configdata[i].setting = pstrdup(CONFIGURE_ARGS);
 	i++;
 
 	configdata[i].name = pstrdup("CC");
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index c208dcdfc7..c8384c6c04 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -42,6 +42,9 @@
    Changing BLCKSZ requires an initdb. */
 #undef BLCKSZ
 
+/* Arguments passed to configure */
+#undef CONFIGURE_ARGS
+
 /* Define to the default TCP port number on which the server listens and to
    which clients will try to connect. This can be overridden at run-time, but
    it's convenient if your clients have the right default compiled in.
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 5f72530c72..e9efc97e14 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -247,7 +247,7 @@ sub GenerateFiles
 			print $o "#define DEF_PGPORT $port\n";
 			print $o "#define DEF_PGPORT_STR \"$port\"\n";
 		}
-		print $o "#define VAL_CONFIGURE \""
+		print $o "#define CONFIGURE_ARGS \""
 		  . $self->GetFakeConfigure() . "\"\n";
 		print $o "#endif /* IGNORE_CONFIGURED_SETTINGS */\n";
 		close($o);
-- 
2.24.0



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

* Re: Simplify passing of configure arguments to pg_config
@ 2019-12-03 05:03  Tom Lane <[email protected]>
  parent: Peter Eisentraut <[email protected]>
  0 siblings, 1 reply; 268+ messages in thread

From: Tom Lane @ 2019-12-03 05:03 UTC (permalink / raw)
  To: Peter Eisentraut <[email protected]>; +Cc: pgsql-hackers

Peter Eisentraut <[email protected]> writes:
> Currently, configure puts the configure args into the makefiles and
> then have the makefiles pass them to the build of pg_config.  That looks 
> like an unnecessary redirection, and indeed that method was
> put in place when pg_config was a shell script.  We can simplify that
> by having configure put the value into pg_config.h directly.  This
> also makes the standard build system match how the MSVC build system
> already does it.

I dunno, is this really an improvement?  It makes the handling of
VAL_CONFIGURE different from every other one of the values passed
into pg_config, and I don't see any countervailing addition of
some other regularity.  I'm also a bit suspicious of the ad-hoc
escaping step ...

			regards, tom lane





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

* Re: Simplify passing of configure arguments to pg_config
@ 2019-12-04 10:30  Peter Eisentraut <[email protected]>
  parent: Tom Lane <[email protected]>
  0 siblings, 1 reply; 268+ messages in thread

From: Peter Eisentraut @ 2019-12-04 10:30 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; +Cc: pgsql-hackers

On 2019-12-03 06:03, Tom Lane wrote:
> Peter Eisentraut <[email protected]> writes:
>> Currently, configure puts the configure args into the makefiles and
>> then have the makefiles pass them to the build of pg_config.  That looks
>> like an unnecessary redirection, and indeed that method was
>> put in place when pg_config was a shell script.  We can simplify that
>> by having configure put the value into pg_config.h directly.  This
>> also makes the standard build system match how the MSVC build system
>> already does it.
> 
> I dunno, is this really an improvement?  It makes the handling of
> VAL_CONFIGURE different from every other one of the values passed
> into pg_config, and I don't see any countervailing addition of
> some other regularity.

The other values come from the makefiles, so we have to do it that way. 
The configure args come from configure, so why make them go through the 
makefile?  (PG_VERSION also comes in that way. ;-) )

There is also the weird difference with how the MSVC build system 
handles it.  It appends VAL_CONFIGURE to pg_config.h instead of passing 
it on the command line.

> I'm also a bit suspicious of the ad-hoc escaping step ...

Hmm, the current way doesn't handle embedded quotes at all, so perhaps 
this wouldn't be necessary.  But it would add some robustness.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services





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

* Re: Simplify passing of configure arguments to pg_config
@ 2019-12-22 13:56  Peter Eisentraut <[email protected]>
  parent: Peter Eisentraut <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Peter Eisentraut @ 2019-12-22 13:56 UTC (permalink / raw)
  To: pgsql-hackers; +Cc: Tom Lane <[email protected]>

On 2019-12-04 11:30, Peter Eisentraut wrote:
> On 2019-12-03 06:03, Tom Lane wrote:
>> Peter Eisentraut <[email protected]> writes:
>>> Currently, configure puts the configure args into the makefiles and
>>> then have the makefiles pass them to the build of pg_config.  That looks
>>> like an unnecessary redirection, and indeed that method was
>>> put in place when pg_config was a shell script.  We can simplify that
>>> by having configure put the value into pg_config.h directly.  This
>>> also makes the standard build system match how the MSVC build system
>>> already does it.
>>
>> I dunno, is this really an improvement?  It makes the handling of
>> VAL_CONFIGURE different from every other one of the values passed
>> into pg_config, and I don't see any countervailing addition of
>> some other regularity.
> 
> The other values come from the makefiles, so we have to do it that way.
> The configure args come from configure, so why make them go through the
> makefile?  (PG_VERSION also comes in that way. ;-) )
> 
> There is also the weird difference with how the MSVC build system
> handles it.  It appends VAL_CONFIGURE to pg_config.h instead of passing
> it on the command line.

Here is an updated version of the patch after the removal of 
pg_config.h.win32.  It's easier to see now how this helps unify the 
handling of this between the two build systems.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

From 459c1ec0708348ea1db8d23d789fa8e391904867 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Sun, 22 Dec 2019 14:50:47 +0100
Subject: [PATCH v2] Simplify passing of configure arguments to pg_config

The previous system had configure put the value into the makefiles and
then have the makefiles pass them to the build of pg_config.  That was
put in place when pg_config was a shell script.  We can simplify that
by having configure put the value into pg_config.h directly.  This
also makes the standard build system match how the MSVC build system
already does it.
---
 configure                  | 6 ++++--
 configure.in               | 2 +-
 src/Makefile.global.in     | 3 ---
 src/common/Makefile        | 1 -
 src/common/config_info.c   | 6 +-----
 src/include/pg_config.h.in | 3 +++
 src/tools/msvc/Solution.pm | 7 +------
 7 files changed, 10 insertions(+), 18 deletions(-)

diff --git a/configure b/configure
index 9de50377ff..ef0e9ac6ca 100755
--- a/configure
+++ b/configure
@@ -776,7 +776,6 @@ build_vendor
 build_cpu
 build
 PG_MAJORVERSION
-configure_args
 target_alias
 host_alias
 build_alias
@@ -2797,7 +2796,10 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 
 
-configure_args=$ac_configure_args
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIGURE_ARGS "$ac_configure_args"
+_ACEOF
 
 
 PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`
diff --git a/configure.in b/configure.in
index 9c5e5e7f8c..c5323ff9b4 100644
--- a/configure.in
+++ b/configure.in
@@ -27,7 +27,7 @@ AC_COPYRIGHT([Copyright (c) 1996-2019, PostgreSQL Global Development Group])
 AC_CONFIG_SRCDIR([src/backend/access/common/heaptuple.c])
 AC_CONFIG_AUX_DIR(config)
 AC_PREFIX_DEFAULT(/usr/local/pgsql)
-AC_SUBST(configure_args, [$ac_configure_args])
+AC_DEFINE_UNQUOTED(CONFIGURE_ARGS, ["$ac_configure_args"], [Saved arguments from configure])
 
 [PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`]
 AC_SUBST(PG_MAJORVERSION)
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 05b66380e0..95f5a104e5 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -74,9 +74,6 @@ endif # not PGXS
 
 vpathsearch = `for f in $(addsuffix /$(1),$(subst :, ,. $(VPATH))); do test -r $$f && echo $$f && break; done`
 
-# Saved arguments from configure
-configure_args = @configure_args@
-
 
 ##########################################################################
 #
diff --git a/src/common/Makefile b/src/common/Makefile
index ffb0f6edff..fd43558830 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -31,7 +31,6 @@ include $(top_builddir)/src/Makefile.global
 # don't include subdirectory-path-dependent -I and -L switches
 STD_CPPFLAGS := $(filter-out -I$(top_srcdir)/src/include -I$(top_builddir)/src/include,$(CPPFLAGS))
 STD_LDFLAGS := $(filter-out -L$(top_builddir)/src/common -L$(top_builddir)/src/port,$(LDFLAGS))
-override CPPFLAGS += -DVAL_CONFIGURE="\"$(configure_args)\""
 override CPPFLAGS += -DVAL_CC="\"$(CC)\""
 override CPPFLAGS += -DVAL_CPPFLAGS="\"$(STD_CPPFLAGS)\""
 override CPPFLAGS += -DVAL_CFLAGS="\"$(CFLAGS)\""
diff --git a/src/common/config_info.c b/src/common/config_info.c
index dd34fbfc00..902f8226a4 100644
--- a/src/common/config_info.c
+++ b/src/common/config_info.c
@@ -124,11 +124,7 @@ get_configdata(const char *my_exec_path, size_t *configdata_len)
 	i++;
 
 	configdata[i].name = pstrdup("CONFIGURE");
-#ifdef VAL_CONFIGURE
-	configdata[i].setting = pstrdup(VAL_CONFIGURE);
-#else
-	configdata[i].setting = pstrdup(_("not recorded"));
-#endif
+	configdata[i].setting = pstrdup(CONFIGURE_ARGS);
 	i++;
 
 	configdata[i].name = pstrdup("CC");
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 050c48b108..97d98751ef 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -42,6 +42,9 @@
    Changing BLCKSZ requires an initdb. */
 #undef BLCKSZ
 
+/* Saved arguments from configure */
+#undef CONFIGURE_ARGS
+
 /* Define to the default TCP port number on which the server listens and to
    which clients will try to connect. This can be overridden at run-time, but
    it's convenient if your clients have the right default compiled in.
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 909bded592..4c7fc7bc30 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -195,6 +195,7 @@ sub GenerateFiles
 		ALIGNOF_SHORT              => 2,
 		AC_APPLE_UNIVERSAL_BUILD   => undef,
 		BLCKSZ                     => 1024 * $self->{options}->{blocksize},
+		CONFIGURE_ARGS             => '"' . $self->GetFakeConfigure() . '"',
 		DEF_PGPORT                 => $port,
 		DEF_PGPORT_STR             => qq{"$port"},
 		ENABLE_GSS                 => $self->{options}->{gss} ? 1 : undef,
@@ -533,12 +534,6 @@ sub GenerateFiles
 	$self->GenerateConfigHeader('src/include/pg_config_ext.h', \%define, 0);
 	$self->GenerateConfigHeader('src/interfaces/ecpg/include/ecpg_config.h', \%define, 0);
 
-	open(my $f, '>>', 'src/include/pg_config.h')
-	  || confess "Could not write to src/include/pg_config.h\n";
-	print $f "\n";
-	print $f "#define VAL_CONFIGURE \"" . $self->GetFakeConfigure() . "\"\n";
-	close($f);
-
 	$self->GenerateDefFile(
 		"src/interfaces/libpq/libpqdll.def",
 		"src/interfaces/libpq/exports.txt",
-- 
2.24.1



Attachments:

  [text/plain] v2-0001-Simplify-passing-of-configure-arguments-to-pg_con.patch (5.2K, ../../[email protected]/2-v2-0001-Simplify-passing-of-configure-arguments-to-pg_con.patch)
  download | inline diff:
From 459c1ec0708348ea1db8d23d789fa8e391904867 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Sun, 22 Dec 2019 14:50:47 +0100
Subject: [PATCH v2] Simplify passing of configure arguments to pg_config

The previous system had configure put the value into the makefiles and
then have the makefiles pass them to the build of pg_config.  That was
put in place when pg_config was a shell script.  We can simplify that
by having configure put the value into pg_config.h directly.  This
also makes the standard build system match how the MSVC build system
already does it.
---
 configure                  | 6 ++++--
 configure.in               | 2 +-
 src/Makefile.global.in     | 3 ---
 src/common/Makefile        | 1 -
 src/common/config_info.c   | 6 +-----
 src/include/pg_config.h.in | 3 +++
 src/tools/msvc/Solution.pm | 7 +------
 7 files changed, 10 insertions(+), 18 deletions(-)

diff --git a/configure b/configure
index 9de50377ff..ef0e9ac6ca 100755
--- a/configure
+++ b/configure
@@ -776,7 +776,6 @@ build_vendor
 build_cpu
 build
 PG_MAJORVERSION
-configure_args
 target_alias
 host_alias
 build_alias
@@ -2797,7 +2796,10 @@ ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
 
 
 
-configure_args=$ac_configure_args
+
+cat >>confdefs.h <<_ACEOF
+#define CONFIGURE_ARGS "$ac_configure_args"
+_ACEOF
 
 
 PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`
diff --git a/configure.in b/configure.in
index 9c5e5e7f8c..c5323ff9b4 100644
--- a/configure.in
+++ b/configure.in
@@ -27,7 +27,7 @@ AC_COPYRIGHT([Copyright (c) 1996-2019, PostgreSQL Global Development Group])
 AC_CONFIG_SRCDIR([src/backend/access/common/heaptuple.c])
 AC_CONFIG_AUX_DIR(config)
 AC_PREFIX_DEFAULT(/usr/local/pgsql)
-AC_SUBST(configure_args, [$ac_configure_args])
+AC_DEFINE_UNQUOTED(CONFIGURE_ARGS, ["$ac_configure_args"], [Saved arguments from configure])
 
 [PG_MAJORVERSION=`expr "$PACKAGE_VERSION" : '\([0-9][0-9]*\)'`]
 AC_SUBST(PG_MAJORVERSION)
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 05b66380e0..95f5a104e5 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -74,9 +74,6 @@ endif # not PGXS
 
 vpathsearch = `for f in $(addsuffix /$(1),$(subst :, ,. $(VPATH))); do test -r $$f && echo $$f && break; done`
 
-# Saved arguments from configure
-configure_args = @configure_args@
-
 
 ##########################################################################
 #
diff --git a/src/common/Makefile b/src/common/Makefile
index ffb0f6edff..fd43558830 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -31,7 +31,6 @@ include $(top_builddir)/src/Makefile.global
 # don't include subdirectory-path-dependent -I and -L switches
 STD_CPPFLAGS := $(filter-out -I$(top_srcdir)/src/include -I$(top_builddir)/src/include,$(CPPFLAGS))
 STD_LDFLAGS := $(filter-out -L$(top_builddir)/src/common -L$(top_builddir)/src/port,$(LDFLAGS))
-override CPPFLAGS += -DVAL_CONFIGURE="\"$(configure_args)\""
 override CPPFLAGS += -DVAL_CC="\"$(CC)\""
 override CPPFLAGS += -DVAL_CPPFLAGS="\"$(STD_CPPFLAGS)\""
 override CPPFLAGS += -DVAL_CFLAGS="\"$(CFLAGS)\""
diff --git a/src/common/config_info.c b/src/common/config_info.c
index dd34fbfc00..902f8226a4 100644
--- a/src/common/config_info.c
+++ b/src/common/config_info.c
@@ -124,11 +124,7 @@ get_configdata(const char *my_exec_path, size_t *configdata_len)
 	i++;
 
 	configdata[i].name = pstrdup("CONFIGURE");
-#ifdef VAL_CONFIGURE
-	configdata[i].setting = pstrdup(VAL_CONFIGURE);
-#else
-	configdata[i].setting = pstrdup(_("not recorded"));
-#endif
+	configdata[i].setting = pstrdup(CONFIGURE_ARGS);
 	i++;
 
 	configdata[i].name = pstrdup("CC");
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 050c48b108..97d98751ef 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -42,6 +42,9 @@
    Changing BLCKSZ requires an initdb. */
 #undef BLCKSZ
 
+/* Saved arguments from configure */
+#undef CONFIGURE_ARGS
+
 /* Define to the default TCP port number on which the server listens and to
    which clients will try to connect. This can be overridden at run-time, but
    it's convenient if your clients have the right default compiled in.
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 909bded592..4c7fc7bc30 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -195,6 +195,7 @@ sub GenerateFiles
 		ALIGNOF_SHORT              => 2,
 		AC_APPLE_UNIVERSAL_BUILD   => undef,
 		BLCKSZ                     => 1024 * $self->{options}->{blocksize},
+		CONFIGURE_ARGS             => '"' . $self->GetFakeConfigure() . '"',
 		DEF_PGPORT                 => $port,
 		DEF_PGPORT_STR             => qq{"$port"},
 		ENABLE_GSS                 => $self->{options}->{gss} ? 1 : undef,
@@ -533,12 +534,6 @@ sub GenerateFiles
 	$self->GenerateConfigHeader('src/include/pg_config_ext.h', \%define, 0);
 	$self->GenerateConfigHeader('src/interfaces/ecpg/include/ecpg_config.h', \%define, 0);
 
-	open(my $f, '>>', 'src/include/pg_config.h')
-	  || confess "Could not write to src/include/pg_config.h\n";
-	print $f "\n";
-	print $f "#define VAL_CONFIGURE \"" . $self->GetFakeConfigure() . "\"\n";
-	close($f);
-
 	$self->GenerateDefFile(
 		"src/interfaces/libpq/libpqdll.def",
 		"src/interfaces/libpq/exports.txt",
-- 
2.24.1



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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

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

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

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


--cpok4wp6gsarlzvp--





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

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

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread

* [PATCH v6] README for 64bit xid
@ 2022-01-10 19:20  Pavel Borisov <[email protected]>
  0 siblings, 0 replies; 268+ messages in thread

From: Pavel Borisov @ 2022-01-10 19:20 UTC (permalink / raw)

Authors:
- Pavel Borisov <[email protected]>
- Maxim Orlov <[email protected]>
- Yura Sokolov <[email protected]> <[email protected]>
---
 src/backend/access/heap/README.XID64 | 128 +++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/backend/access/heap/README.XID64

diff --git a/src/backend/access/heap/README.XID64 b/src/backend/access/heap/README.XID64
new file mode 100644
index 00000000000..457ba9b9ef5
--- /dev/null
+++ b/src/backend/access/heap/README.XID64
@@ -0,0 +1,128 @@
+src/backend/access/heap/README.XID64
+
+64-bit Transaction ID's (XID)
+=============================
+
+A limited number (N = 2^32) of XID's required to do vacuum freeze to prevent
+wraparound every N/2 transactions. This causes performance degradation due
+to the need to exclusively lock tables while being vacuumed. In each
+wraparound cycle, SLRU buffers are also being cut.
+
+With 64-bit XID's wraparound is effectively postponed to a very distant
+future. Even in highly loaded systems that had 2^32 transactions per day
+it will take huge 2^31 days before the first enforced "vacuum to prevent
+wraparound"). Buffers cutting and routine vacuum are not enforced, and DBA
+can plan them independently at the time with the least system load and least
+critical for database performance. Also, it can be done less frequently
+(several times a year vs every several days) on systems with transaction rates
+similar to those mentioned above.
+
+On-disk tuple and page format
+-----------------------------
+
+On-disk tuple format remains unchanged. 32-bit t_xmin and t_xmax store the
+lower parts of 64-bit XMIN and XMAX values. Each heap page has additional
+64-bit pd_xid_base and pd_multi_base which are common for all tuples on a page.
+They are placed into a pd_special area - 16 bytes in the end of a heap page.
+Actual XMIN/XMAX for a tuple are calculated upon reading a tuple from a page
+as follows:
+
+XMIN = t_xmin + pd_xid_base. 					(1)
+XMAX = t_xmax + pd_xid_base/pd_multi_base.		(2)
+
+"Double XMAX" page format
+---------------------------------
+
+At first read of a heap page after pg_upgrade from 32-bit XID PostgreSQL
+version pd_special area with a size of 16 bytes should be added to a page.
+Though a page may not have space for this. Then it can be converted to a
+temporary format called "double XMAX".
+
+All tuples after pg-upgrade would necessarily have xmin = FrozenTransactionId.
+So we don't need tuple header t_xmin field and we reuse t_xmin to store higher
+32 bits of its XMAX.
+
+Double XMAX format is only for full pages that don't have 16 bytes for
+pd_special. So it neither has a�place for a single tuple. Insert and HOT update
+for double XMAX pages is impossible and not supported. We can only read or
+delete tuples from it.
+
+When we are able to prune page double XMAX it will be converted from it to
+general 64-bit XID page format with all operations on its tuples supported.
+
+In-memory tuple format
+----------------------
+
+In-memory tuple representation consists of two parts:
+- HeapTupleHeader from disk page (contains all heap tuple contents, not only
+header)
+- HeapTuple with additional in-memory fields
+
+HeapTuple for each tuple in memory stores t_xid_base/t_multi_base - a copies of
+page's pd_xid_base/pd_multi_base. With tuple's 32-bit t_xmin and t_xmax from
+HeapTupleHeader they are used to calculate actual 64-bit XMIN and XMAX:
+
+XMIN = t_xmin + t_xid_base. 					(3)
+XMAX = t_xmax + t_xid_base/t_multi_base.		(4)
+
+The downside of this is that we can not use tuple's XMIN and XMAX right away.
+We often need to re-read t_xmin and t_xmax - which could actually be pointers
+into a page in shared buffers and therefore they could be updated by any other
+backend.
+
+Update/delete with 64-bit XIDs and 32-bit t_xmin/t_xmax
+--------------------------------------------------------------
+
+When we try to delete/update a tuple, we check that XMAX for a page fits (2).
+I.e. that t_xmax will not be over MaxShortTransactionId relative to
+pd_xid_base/pd_multi_base of a its page.
+
+If the current XID doesn't fit a range
+(pd_xid_base, pd_xid_base + MaxShortTransactionId) (5):
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base/pd_multi_base on
+a page and update all t_xmin/t_xmax of the other tuples on the page to
+correspond new pd_xid_base/pd_multi_base.
+
+- If it was impossible, it will try to prune and freeze tuples on a page.
+
+- If this is unsuccessful it will throw an error. Normally this is very
+unlikely but if there is a very old living transaction with an age of around
+2^32 this can arise. Basically, this is a behavior similar to one during the
+vacuum to prevent wraparound when XID was 32-bit. Dba should take care and
+avoid very-long-living transactions with an age close to 2^32. So long-living
+transactions often they are most likely defunct.
+
+Insert with 64-bit XIDs and 32-bit t_xmin/t_xmax
+------------------------------------------------
+
+On insert we check if current XID fits a range (5). Otherwise:
+
+- heap_page_prepare_for_xid() will try to increase pd_xid_base for t_xmin will
+not be over MaxShortTransactionId.
+
+- If it is impossible, then it will try to prune and freeze tuples on a page.
+
+Known issue: if pd_xid_base could not be shifted to accommodate a tuple being
+inserted due to a very long-running transaction, we just throw an error. We
+neither try to insert a�tuple into another page nor mark the current page as
+full. So, in this (unlikely) case we will get regular insert errors on the next
+tries to insert to the page 'locked' by this very long-running transaction.
+
+Upgrade from 32-bit XID versions
+--------------------------------
+
+pg_upgrade doesn't change pages format itself. It is done lazily after.
+
+1. At first heap page read, tuples on a page are repacked to free 16 bytes
+at the end of a page, possibly freeing space from dead tuples.
+
+2A. 16 bytes of pd_special is added if there is a place for it
+
+2B. Page is converted to "Double XMAX" format if there is no place for
+pd_special
+
+3. If a page is in double XMAX format after its first read, and vacuum (or
+micro-vacuum at select query) could prune some tuples and free space for
+pd_special, prune_page will add pd_special and convert page from double XMAX
+to general 64-bit XID page format.
-- 
2.24.3 (Apple Git-128)


--cpok4wp6gsarlzvp--





^ permalink  raw  reply  [nested|flat] 268+ messages in thread


end of thread, other threads:[~2022-01-10 19:20 UTC | newest]

Thread overview: 268+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2019-12-02 12:27 Simplify passing of configure arguments to pg_config Peter Eisentraut <[email protected]>
2019-12-03 05:03 ` Tom Lane <[email protected]>
2019-12-04 10:30   ` Peter Eisentraut <[email protected]>
2019-12-22 13:56     ` Peter Eisentraut <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH v6] README for 64bit xid Pavel Borisov <[email protected]>
2022-01-10 19:20 [PATCH 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