Skip to content

Commit e039b09

Browse files
committed
Fix pg_upgrade around multixid and mxoff wraparound
pg_resetwal didn't accept multixid 0 or multixact offset UINT32_MAX, but they are both valid values that can appear in the control file. That caused pg_upgrade to fail if you tried to upgrade a cluster exactly at multixid or offset wraparound, because pg_upgrade calls pg_resetwal to restore multixid/offset on the new cluster to the values from the old cluster. To fix, allow those values in pg_resetwal. Fixes bugs #18863 and #18865 reported by Dmitry Kovalenko. Backpatch down to v15. Version 14 has the same bug, but the patch doesn't apply cleanly there. It could be made to work but it doesn't seem worth the effort given how rare it is to hit this problem with pg_upgrade, and how few people are upgrading to v14 anymore. Author: Maxim Orlov <orlovmg@gmail.com> Discussion: https://www.postgresql.org/message-id/CACG%3DezaApSMTjd%3DM2Sfn5Ucuggd3FG8Z8Qte8Xq9k5-%2BRQis-g@mail.gmail.com Discussion: https://www.postgresql.org/message-id/18863-72f08858855344a2@postgresql.org Discussion: https://www.postgresql.org/message-id/18865-d4c66cf35c2a67af@postgresql.org Backpatch-through: 15
1 parent 807df49 commit e039b09

File tree

1 file changed

+15
-10
lines changed

1 file changed

+15
-10
lines changed

src/bin/pg_resetwal/pg_resetwal.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,10 @@ static TransactionId set_xid = 0;
6969
static TransactionId set_oldest_commit_ts_xid = 0;
7070
static TransactionId set_newest_commit_ts_xid = 0;
7171
static Oid set_oid = 0;
72+
static bool mxid_given = false;
7273
static MultiXactId set_mxid = 0;
73-
static MultiXactOffset set_mxoff = (MultiXactOffset) -1;
74+
static bool mxoff_given = false;
75+
static MultiXactOffset set_mxoff = 0;
7476
static TimeLineID minXlogTli = 0;
7577
static XLogSegNo minXlogSegNo = 0;
7678
static int WalSegSz;
@@ -114,6 +116,7 @@ main(int argc, char *argv[])
114116
MultiXactId set_oldestmxid = 0;
115117
char *endptr;
116118
char *endptr2;
119+
int64 tmpi64;
117120
char *DataDir = NULL;
118121
char *log_fname = NULL;
119122
int fd;
@@ -250,28 +253,30 @@ main(int argc, char *argv[])
250253
pg_log_error_hint("Try \"%s --help\" for more information.", progname);
251254
exit(1);
252255
}
253-
if (set_mxid == 0)
254-
pg_fatal("multitransaction ID (-m) must not be 0");
255256

256257
/*
257258
* XXX It'd be nice to have more sanity checks here, e.g. so
258259
* that oldest is not wrapped around w.r.t. nextMulti.
259260
*/
260261
if (set_oldestmxid == 0)
261262
pg_fatal("oldest multitransaction ID (-m) must not be 0");
263+
mxid_given = true;
262264
break;
263265

264266
case 'O':
265267
errno = 0;
266-
set_mxoff = strtoul(optarg, &endptr, 0);
268+
tmpi64 = strtoi64(optarg, &endptr, 0);
267269
if (endptr == optarg || *endptr != '\0' || errno != 0)
268270
{
269271
pg_log_error("invalid argument for option %s", "-O");
270272
pg_log_error_hint("Try \"%s --help\" for more information.", progname);
271273
exit(1);
272274
}
273-
if (set_mxoff == -1)
274-
pg_fatal("multitransaction offset (-O) must not be -1");
275+
if (tmpi64 < 0 || tmpi64 > (int64) MaxMultiXactOffset)
276+
pg_fatal("multitransaction offset (-O) must be between 0 and %u", MaxMultiXactOffset);
277+
278+
set_mxoff = (MultiXactOffset) tmpi64;
279+
mxoff_given = true;
275280
break;
276281

277282
case 'l':
@@ -430,7 +435,7 @@ main(int argc, char *argv[])
430435
if (set_oid != 0)
431436
ControlFile.checkPointCopy.nextOid = set_oid;
432437

433-
if (set_mxid != 0)
438+
if (mxid_given)
434439
{
435440
ControlFile.checkPointCopy.nextMulti = set_mxid;
436441

@@ -440,7 +445,7 @@ main(int argc, char *argv[])
440445
ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
441446
}
442447

443-
if (set_mxoff != -1)
448+
if (mxoff_given)
444449
ControlFile.checkPointCopy.nextMultiOffset = set_mxoff;
445450

446451
if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
@@ -790,7 +795,7 @@ PrintNewControlValues(void)
790795
newXlogSegNo, WalSegSz);
791796
printf(_("First log segment after reset: %s\n"), fname);
792797

793-
if (set_mxid != 0)
798+
if (mxid_given)
794799
{
795800
printf(_("NextMultiXactId: %u\n"),
796801
ControlFile.checkPointCopy.nextMulti);
@@ -800,7 +805,7 @@ PrintNewControlValues(void)
800805
ControlFile.checkPointCopy.oldestMultiDB);
801806
}
802807

803-
if (set_mxoff != -1)
808+
if (mxoff_given)
804809
{
805810
printf(_("NextMultiOffset: %u\n"),
806811
ControlFile.checkPointCopy.nextMultiOffset);

0 commit comments

Comments
 (0)