This patch has been applied back to 9.6 and will appear in the next
minor release.

---------------------------------------------------------------------------

On Tue, May 18, 2021 at 01:26:38PM +0200, Drouvot, Bertrand wrote:
> Hi,
> 
> On 5/4/21 10:17 AM, Drouvot, Bertrand wrote:
> 
> 
>     Hi,
> 
>     On 4/24/21 3:00 AM, Andres Freund wrote:
> 
>         Hi,
> 
>         On 2021-04-23 19:28:27 -0500, Justin Pryzby wrote:
> 
>             This (combination of) thread(s) seems relevant.
> 
>             Subject: pg_upgrade failing for 200+ million Large Objects
>             
> https://www.postgresql.org/message-id/flat/12601596dbbc4c01b86b4ac4d2bd4d48%40EX13D05UWC001.ant.amazon.com
>             
> https://www.postgresql.org/message-id/flat/a9f9376f1c3343a6bb319dce294e20ac%40EX13D05UWC001.ant.amazon.com
>             
> https://www.postgresql.org/message-id/flat/cc089cc3-fc43-9904-fdba-d830d8222145%40enterprisedb.com#3eec85391c6076a4913e96a86fece75e
> 
>         Huh. Thanks for digging these up.
> 
> 
> 
>                 Allows the user to provide a constant via pg_upgrade 
> command-line, that
>                 overrides the 2 billion constant in pg_resetxlog [1] thereby 
> increasing the
>                 (window of) Transaction IDs available for pg_upgrade to 
> complete.
> 
>         That seems the entirely the wrong approach to me, buying further into
>         the broken idea of inventing random wrong values for oldestXid.
> 
>         We drive important things like the emergency xid limits off 
> oldestXid. On
>         databases with tables that are older than ~147million xids (i.e. not 
> even
>         affected by the default autovacuum_freeze_max_age) the current 
> constant leads
>         to setting the oldestXid to a value *in the future*/wrapped around. 
> Any
>         different different constant (or pg_upgrade parameter) will do that 
> too in
>         other scenarios.
> 
>         As far as I can tell there is precisely *no* correct behaviour here 
> other than
>         exactly copying the oldestXid limit from the source database.
> 
> 
>     Please find attached a patch proposal doing so: it adds a new (- u)
>     parameter to pg_resetwal that allows to specify the oldest unfrozen XID to
>     set.
>     Then this new parameter is being used in pg_upgrade to copy the source
>     Latest checkpoint's oldestXID.
> 
>     Questions:
> 
>       □ Should we keep the old behavior in case -x is being used without -u?
>         (The proposed patch does not set an arbitrary oldestXID anymore in 
> case
>         -x is used.)
>       □ Also shouldn't we ensure that the xid provided with -x or -u is >=
>         FirstNormalTransactionId (Currently the only check is that it is # 0)?
> 
> 
> Copy/pasting Andres feedback (Thanks Andres for this feedback) on those
> questions from another thread [1].
> 
> > I was also wondering if:
> >
> > * We should keep the old behavior in case pg_resetwal -x is being used
> > without -u?
 (The proposed patch does not set an arbitrary oldestXID
> > anymore in 
case -x is used)
> 
> Andres: I don't think we should. I don't see anything in the old behaviour
> worth
> maintaining.
> 
> > * We should ensure that the xid provided with -x or -u is
> > >=
FirstNormalTransactionId (Currently the only check is that it is
> > # 0)?
> 
> Andres: Applying TransactionIdIsNormal() seems like a good idea.
> 
> => I am attaching a new version that makes use of TransactionIdIsNormal()
> checks.
> 
> Andres: I think it's important to verify that the xid provided with -x is
> within a reasonable range of the oldest xid.
> 
> => What do you mean by "a reasonable range"?
> 
> Thanks
> 
> Bertrand
> 
> [1]: https://www.postgresql.org/message-id/
> 20210517185646.pwe4klaufwmdhe2a%40alap3.anarazel.de
> 
> 
> 
> 

>  src/bin/pg_resetwal/pg_resetwal.c | 65 
> ++++++++++++++++++++++-----------------
>  src/bin/pg_upgrade/controldata.c  | 17 +++++++++-
>  src/bin/pg_upgrade/pg_upgrade.c   |  6 ++++
>  src/bin/pg_upgrade/pg_upgrade.h   |  1 +
>  4 files changed, 60 insertions(+), 29 deletions(-)
> diff --git a/src/bin/pg_resetwal/pg_resetwal.c 
> b/src/bin/pg_resetwal/pg_resetwal.c
> index 805dafef07..5e864760ed 100644
> --- a/src/bin/pg_resetwal/pg_resetwal.c
> +++ b/src/bin/pg_resetwal/pg_resetwal.c
> @@ -65,6 +65,7 @@ static bool guessed = false;        /* T if we had to guess 
> at any values */
>  static const char *progname;
>  static uint32 set_xid_epoch = (uint32) -1;
>  static TransactionId set_xid = 0;
> +static TransactionId set_oldest_unfrozen_xid = 0;
>  static TransactionId set_oldest_commit_ts_xid = 0;
>  static TransactionId set_newest_commit_ts_xid = 0;
>  static Oid   set_oid = 0;
> @@ -102,6 +103,7 @@ main(int argc, char *argv[])
>               {"next-oid", required_argument, NULL, 'o'},
>               {"multixact-offset", required_argument, NULL, 'O'},
>               {"next-transaction-id", required_argument, NULL, 'x'},
> +             {"oldest-transaction-id", required_argument, NULL, 'u'},
>               {"wal-segsize", required_argument, NULL, 1},
>               {NULL, 0, NULL, 0}
>       };
> @@ -135,7 +137,7 @@ main(int argc, char *argv[])
>       }
>  
>  
> -     while ((c = getopt_long(argc, argv, "c:D:e:fl:m:no:O:x:", long_options, 
> NULL)) != -1)
> +     while ((c = getopt_long(argc, argv, "c:D:e:fl:m:no:O:x:u:", 
> long_options, NULL)) != -1)
>       {
>               switch (c)
>               {
> @@ -176,9 +178,24 @@ main(int argc, char *argv[])
>                                       fprintf(stderr, _("Try \"%s --help\" 
> for more information.\n"), progname);
>                                       exit(1);
>                               }
> -                             if (set_xid == 0)
> +                             if (!TransactionIdIsNormal(set_xid))
>                               {
> -                                     pg_log_error("transaction ID (-x) must 
> not be 0");
> +                                     pg_log_error("transaction ID (-x) must 
> be greater or equal to %u", FirstNormalTransactionId);
> +                                     exit(1);
> +                             }
> +                             break;
> +
> +                     case 'u':
> +                             set_oldest_unfrozen_xid = strtoul(optarg, 
> &endptr, 0);
> +                             if (endptr == optarg || *endptr != '\0')
> +                             {
> +                                     pg_log_error("invalid argument for 
> option %s", "-u");
> +                                     fprintf(stderr, _("Try \"%s --help\" 
> for more information.\n"), progname);
> +                                     exit(1);
> +                             }
> +                             if 
> (!TransactionIdIsNormal(set_oldest_unfrozen_xid))
> +                             {
> +                                     pg_log_error("oldest unfrozen 
> transaction ID (-u) must be greater or equal to %u", 
> FirstNormalTransactionId);
>                                       exit(1);
>                               }
>                               break;
> @@ -429,21 +446,12 @@ main(int argc, char *argv[])
>                                                                               
>          XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
>  
>       if (set_xid != 0)
> -     {
>               ControlFile.checkPointCopy.nextXid =
>                       
> FullTransactionIdFromEpochAndXid(EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid),
>                                                                               
>          set_xid);
>  
> -             /*
> -              * For the moment, just set oldestXid to a value that will force
> -              * immediate autovacuum-for-wraparound.  It's not clear whether 
> adding
> -              * user control of this is useful, so let's just do something 
> that's
> -              * reasonably safe.  The magic constant here corresponds to the
> -              * maximum allowed value of autovacuum_freeze_max_age.
> -              */
> -             ControlFile.checkPointCopy.oldestXid = set_xid - 2000000000;
> -             if (ControlFile.checkPointCopy.oldestXid < 
> FirstNormalTransactionId)
> -                     ControlFile.checkPointCopy.oldestXid += 
> FirstNormalTransactionId;
> +     if (set_oldest_unfrozen_xid != 0) {
> +             ControlFile.checkPointCopy.oldestXid = set_oldest_unfrozen_xid;
>               ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
>       }
>  
> @@ -1209,20 +1217,21 @@ usage(void)
>       printf(_("Usage:\n  %s [OPTION]... DATADIR\n\n"), progname);
>       printf(_("Options:\n"));
>       printf(_("  -c, --commit-timestamp-ids=XID,XID\n"
> -                      "                                 set oldest and 
> newest transactions bearing\n"
> -                      "                                 commit timestamp 
> (zero means no change)\n"));
> -     printf(_(" [-D, --pgdata=]DATADIR          data directory\n"));
> -     printf(_("  -e, --epoch=XIDEPOCH           set next transaction ID 
> epoch\n"));
> -     printf(_("  -f, --force                    force update to be done\n"));
> -     printf(_("  -l, --next-wal-file=WALFILE    set minimum starting 
> location for new WAL\n"));
> -     printf(_("  -m, --multixact-ids=MXID,MXID  set next and oldest 
> multitransaction ID\n"));
> -     printf(_("  -n, --dry-run                  no update, just show what 
> would be done\n"));
> -     printf(_("  -o, --next-oid=OID             set next OID\n"));
> -     printf(_("  -O, --multixact-offset=OFFSET  set next multitransaction 
> offset\n"));
> -     printf(_("  -V, --version                  output version information, 
> then exit\n"));
> -     printf(_("  -x, --next-transaction-id=XID  set next transaction ID\n"));
> -     printf(_("      --wal-segsize=SIZE         size of WAL segments, in 
> megabytes\n"));
> -     printf(_("  -?, --help                     show this help, then 
> exit\n"));
> +                      "                                   set oldest and 
> newest transactions bearing\n"
> +                      "                                   commit timestamp 
> (zero means no change)\n"));
> +     printf(_(" [-D, --pgdata=]DATADIR            data directory\n"));
> +     printf(_("  -e, --epoch=XIDEPOCH             set next transaction ID 
> epoch\n"));
> +     printf(_("  -f, --force                      force update to be 
> done\n"));
> +     printf(_("  -l, --next-wal-file=WALFILE      set minimum starting 
> location for new WAL\n"));
> +     printf(_("  -m, --multixact-ids=MXID,MXID    set next and oldest 
> multitransaction ID\n"));
> +     printf(_("  -n, --dry-run                    no update, just show what 
> would be done\n"));
> +     printf(_("  -o, --next-oid=OID               set next OID\n"));
> +     printf(_("  -O, --multixact-offset=OFFSET    set next multitransaction 
> offset\n"));
> +     printf(_("  -u, --oldest-transaction-id=XID  set oldest unfrozen 
> transaction ID\n"));
> +     printf(_("  -V, --version                    output version 
> information, then exit\n"));
> +     printf(_("  -x, --next-transaction-id=XID    set next transaction 
> ID\n"));
> +     printf(_("      --wal-segsize=SIZE           size of WAL segments, in 
> megabytes\n"));
> +     printf(_("  -?, --help                       show this help, then 
> exit\n"));
>       printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
>       printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
>  }
> diff --git a/src/bin/pg_upgrade/controldata.c 
> b/src/bin/pg_upgrade/controldata.c
> index 4f647cdf33..a4b6375403 100644
> --- a/src/bin/pg_upgrade/controldata.c
> +++ b/src/bin/pg_upgrade/controldata.c
> @@ -44,6 +44,7 @@ get_control_data(ClusterInfo *cluster, bool live_check)
>       bool            got_oid = false;
>       bool            got_multi = false;
>       bool            got_oldestmulti = false;
> +     bool            got_oldestxid = false;
>       bool            got_mxoff = false;
>       bool            got_nextxlogfile = false;
>       bool            got_float8_pass_by_value = false;
> @@ -312,6 +313,17 @@ get_control_data(ClusterInfo *cluster, bool live_check)
>                       cluster->controldata.chkpnt_nxtmulti = str2uint(p);
>                       got_multi = true;
>               }
> +             else if ((p = strstr(bufin, "Latest checkpoint's oldestXID:")) 
> != NULL)
> +             {
> +                     p = strchr(p, ':');
> +
> +                     if (p == NULL || strlen(p) <= 1)
> +                             pg_fatal("%d: controldata retrieval problem\n", 
> __LINE__);
> +
> +                     p++;                            /* remove ':' char */
> +                     cluster->controldata.chkpnt_oldstxid = str2uint(p);
> +                     got_oldestxid = true;
> +             }
>               else if ((p = strstr(bufin, "Latest checkpoint's 
> oldestMultiXid:")) != NULL)
>               {
>                       p = strchr(p, ':');
> @@ -544,7 +556,7 @@ get_control_data(ClusterInfo *cluster, bool live_check)
>  
>       /* verify that we got all the mandatory pg_control data */
>       if (!got_xid || !got_oid ||
> -             !got_multi ||
> +             !got_multi || !got_oldestxid ||
>               (!got_oldestmulti &&
>                cluster->controldata.cat_ver >= 
> MULTIXACT_FORMATCHANGE_CAT_VER) ||
>               !got_mxoff || (!live_check && !got_nextxlogfile) ||
> @@ -575,6 +587,9 @@ get_control_data(ClusterInfo *cluster, bool live_check)
>                       cluster->controldata.cat_ver >= 
> MULTIXACT_FORMATCHANGE_CAT_VER)
>                       pg_log(PG_REPORT, "  latest checkpoint oldest 
> MultiXactId\n");
>  
> +             if (!got_oldestxid)
> +                     pg_log(PG_REPORT, "  latest checkpoint oldestXID\n");
> +
>               if (!got_mxoff)
>                       pg_log(PG_REPORT, "  latest checkpoint next 
> MultiXactOffset\n");
>  
> diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
> index e23b8ca88d..950ff24980 100644
> --- a/src/bin/pg_upgrade/pg_upgrade.c
> +++ b/src/bin/pg_upgrade/pg_upgrade.c
> @@ -473,6 +473,12 @@ copy_xact_xlog_xid(void)
>                         "\"%s/pg_resetwal\" -f -x %u \"%s\"",
>                         new_cluster.bindir, 
> old_cluster.controldata.chkpnt_nxtxid,
>                         new_cluster.pgdata);
> +     check_ok();
> +     prep_status("Setting oldest XID for new cluster");
> +     exec_prog(UTILITY_LOG_FILE, NULL, true, true,
> +                       "\"%s/pg_resetwal\" -f -u %u \"%s\"",
> +                       new_cluster.bindir, 
> old_cluster.controldata.chkpnt_oldstxid,
> +                       new_cluster.pgdata);
>       exec_prog(UTILITY_LOG_FILE, NULL, true, true,
>                         "\"%s/pg_resetwal\" -f -e %u \"%s\"",
>                         new_cluster.bindir, 
> old_cluster.controldata.chkpnt_nxtepoch,
> diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
> index a5f71c5294..dd0204902c 100644
> --- a/src/bin/pg_upgrade/pg_upgrade.h
> +++ b/src/bin/pg_upgrade/pg_upgrade.h
> @@ -207,6 +207,7 @@ typedef struct
>       uint32          chkpnt_nxtmulti;
>       uint32          chkpnt_nxtmxoff;
>       uint32          chkpnt_oldstMulti;
> +     uint32          chkpnt_oldstxid;
>       uint32          align;
>       uint32          blocksz;
>       uint32          largesz;


-- 
  Bruce Momjian  <br...@momjian.us>        https://momjian.us
  EDB                                      https://enterprisedb.com

  If only the physical world exists, free will is an illusion.



Reply via email to