diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml index 585665f161..67c1c6d8dc 100644 --- a/doc/src/sgml/ref/initdb.sgml +++ b/doc/src/sgml/ref/initdb.sgml @@ -390,6 +390,45 @@ PostgreSQL documentation + + Other options for testing 64-bit XIDs: + + + + + + + + Specifies a start multixact id value in the decimal format for new db instance to test 64-bit xids, + default value is 0. + + + + + + + + + + Specifies a start multixact offset value in the decimal format for new db instance to test 64-bit xids, + default value is 0. + + + + + + + + + + Specifies a start xid value in the decimal for new db instance to test 64-bit xids, + default value is 0. + + + + + + Other options: diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c index 2caaa49360..24250bbc67 100644 --- a/src/backend/access/transam/clog.c +++ b/src/backend/access/transam/clog.c @@ -710,6 +710,9 @@ void BootStrapCLOG(void) { int slotno; + int64 pageno; + + pageno = TransactionIdToPage(ShmemVariableCache->nextXid); LWLockAcquire(CLogControlLock, LW_EXCLUSIVE); @@ -720,6 +723,16 @@ BootStrapCLOG(void) SimpleLruWritePage(ClogCtl, slotno); Assert(!ClogCtl->shared->page_dirty[slotno]); + if (pageno != 0) + { + /* Create and zero the first page of the commit log */ + slotno = ZeroCLOGPage(pageno, false); + + /* Make sure it's written out */ + SimpleLruWritePage(ClogCtl, slotno); + Assert(!ClogCtl->shared->page_dirty[slotno]); + } + LWLockRelease(CLogControlLock); } diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 0e7827022a..3239d7bf9c 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -1666,6 +1666,8 @@ void BootStrapMultiXact(void) { int slotno; + int64 multiOffsetPageno; + int64 multiMemberPageno; LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE); @@ -1676,6 +1678,17 @@ BootStrapMultiXact(void) SimpleLruWritePage(MultiXactOffsetCtl, slotno); Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]); + multiOffsetPageno = MultiXactIdToOffsetPage(MultiXactState->nextMXact - 1); + if (multiOffsetPageno != 0) + { + /* Create and zero the first page of the offsets log */ + slotno = ZeroMultiXactOffsetPage(multiOffsetPageno, false); + + /* Make sure it's written out */ + SimpleLruWritePage(MultiXactOffsetCtl, slotno); + Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]); + } + LWLockRelease(MultiXactOffsetControlLock); LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE); @@ -1687,7 +1700,32 @@ BootStrapMultiXact(void) SimpleLruWritePage(MultiXactMemberCtl, slotno); Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]); + multiMemberPageno = MXOffsetToMemberPage(MultiXactState->nextOffset - 1); + if (multiMemberPageno != 0) + { + /* Create and zero the first page of the members log */ + slotno = ZeroMultiXactMemberPage(multiMemberPageno, false); + + /* Make sure it's written out */ + SimpleLruWritePage(MultiXactMemberCtl, slotno); + Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]); + } + LWLockRelease(MultiXactMemberControlLock); + + /* + * If we're starting not from zero offset, initilize dummy multixact to + * evade too long loop in PerformMembersTruncation(). + */ + if (MultiXactState->nextOffset > 0 && MultiXactState->nextMXact > 0) + { + RecordNewMultiXact(FirstMultiXactId, + MultiXactState->nextOffset, + 0, NULL); + RecordNewMultiXact(MultiXactState->nextMXact - 1, + MultiXactState->nextOffset, + 0, NULL); + } } /* diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c index de79619d08..06fa4526ca 100644 --- a/src/backend/access/transam/subtrans.c +++ b/src/backend/access/transam/subtrans.c @@ -210,11 +210,14 @@ void BootStrapSUBTRANS(void) { int slotno; + int64 pageno; + + pageno = TransactionIdToPage(ShmemVariableCache->nextXid); LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE); /* Create and zero the first page of the subtrans log */ - slotno = ZeroSUBTRANSPage(0); + slotno = ZeroSUBTRANSPage(pageno); /* Make sure it's written out */ SimpleLruWritePage(SubTransCtl, slotno); diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b9bdf7914b..96a3bafec6 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -106,6 +106,10 @@ int CommitDelay = 0; /* precommit delay in microseconds */ int CommitSiblings = 5; /* # concurrent xacts needed to sleep */ int wal_retrieve_retry_interval = 5000; +TransactionId start_xid = 0; +MultiXactId start_mx_id = 0; +MultiXactOffset start_mx_offset = 0; + #ifdef WAL_DEBUG bool XLOG_DEBUG = false; #endif @@ -5053,10 +5057,10 @@ BootStrapXLOG(void) checkPoint.ThisTimeLineID = ThisTimeLineID; checkPoint.PrevTimeLineID = ThisTimeLineID; checkPoint.fullPageWrites = fullPageWrites; - checkPoint.nextXid = FirstNormalTransactionId + 1; + checkPoint.nextXid = Max(FirstNormalTransactionId + 1, start_xid); checkPoint.nextOid = FirstBootstrapObjectId; - checkPoint.nextMulti = FirstMultiXactId + 1; - checkPoint.nextMultiOffset = 1; + checkPoint.nextMulti = Max(FirstMultiXactId + 1, start_mx_id); + checkPoint.nextMultiOffset = Max(start_mx_offset, 1); checkPoint.oldestXid = checkPoint.nextXid - 1; checkPoint.oldestXidDB = TemplateDbOid; checkPoint.oldestMulti = checkPoint.nextMulti - 1; diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 3a3ca5c4c6..36311c2474 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -223,7 +223,10 @@ AuxiliaryProcessMain(int argc, char *argv[]) /* If no -x argument, we are a CheckerProcess */ MyAuxProcType = CheckerProcess; - while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:X:-:")) != -1) + start_xid = 0; + start_mx_id = 0; + start_mx_offset = 0; + while ((flag = getopt(argc, argv, "B:c:d:D:Fkm:o:r:z:x:X:-:")) != -1) { switch (flag) { @@ -252,9 +255,30 @@ AuxiliaryProcessMain(int argc, char *argv[]) case 'k': bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION; break; + case 'm': + if (sscanf(optarg, XID_FMT, &start_mx_id) != 1 + || !StartMultiXactIdIsValid(start_mx_id)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid start multixact id value"))); + break; + case 'o': + if (sscanf(optarg, XID_FMT, &start_mx_offset) != 1 + || !StartMultiXactOffsetIsValid(start_mx_offset)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid start multixact offset value"))); + break; case 'r': strlcpy(OutputFileName, optarg, MAXPGPATH); break; + case 'z': + if (sscanf(optarg, XID_FMT, &start_xid) != 1 + || !StartTransactionIdIsValid(start_xid)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid start xid value"))); + break; case 'x': MyAuxProcType = atoi(optarg); break; diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index 2efd3b75b1..00a6a161eb 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -144,6 +144,9 @@ static bool data_checksums = false; static char *xlog_dir = NULL; static char *str_wal_segment_size_mb = NULL; static int wal_segment_size_mb; +static TransactionId start_xid = 0; +static MultiXactId start_mx_id = 0; +static MultiXactOffset start_mx_offset = 0; /* internal vars */ @@ -1381,10 +1384,13 @@ bootstrap_template1(void) unsetenv("PGCLIENTENCODING"); snprintf(cmd, sizeof(cmd), - "\"%s\" --boot -x1 -X %u %s %s %s", + "\"%s\" --boot -x1 -X %u %s %s " XID_FMT " %s " XID_FMT " %s " XID_FMT " %s %s", backend_exec, wal_segment_size_mb * (1024 * 1024), data_checksums ? "-k" : "", + "-z", start_xid, + "-m", start_mx_id, + "-o", start_mx_offset, boot_options, debug ? "-d 5" : ""); @@ -2323,13 +2329,21 @@ usage(const char *progname) printf(_(" -U, --username=NAME database superuser name\n")); printf(_(" -W, --pwprompt prompt for a password for the new superuser\n")); printf(_(" -X, --waldir=WALDIR location for the write-ahead log directory\n")); + printf(_(" -x, --xid=START_XID specify start xid value in decimal format for new db instance to test 64-bit xids,\n" + " default value is 0, max value is 2^62-1\n")); printf(_(" --wal-segsize=SIZE size of wal segment size\n")); printf(_("\nLess commonly used options:\n")); printf(_(" -d, --debug generate lots of debugging output\n")); printf(_(" -k, --data-checksums use data page checksums\n")); printf(_(" -L DIRECTORY where to find the input files\n")); + printf(_(" -m, --multixact-id=START_MX_ID\n" + " specify start multixact id value in decimal format for new db instance\n" + " to test 64-bit xids, default value is 0, max value is 2^62-1\n")); printf(_(" -n, --no-clean do not clean up after errors\n")); printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n")); + printf(_(" -o, --multixact-offset=START_MX_OFFSET\n" + " specify start multixact offset value in decimal format for new db instance\n" + " to test 64-bit xids, default value is 0, max value is 2^62-1\n")); printf(_(" -s, --show show internal settings\n")); printf(_(" -S, --sync-only only sync data directory\n")); printf(_("\nOther options:\n")); @@ -3016,6 +3030,9 @@ main(int argc, char *argv[]) {"waldir", required_argument, NULL, 'X'}, {"wal-segsize", required_argument, NULL, 12}, {"data-checksums", no_argument, NULL, 'k'}, + {"xid", required_argument, NULL, 'x'}, + {"multixact-id", required_argument, NULL, 'm'}, + {"multixact-offset", required_argument, NULL, 'o'}, {NULL, 0, NULL, 0} }; @@ -3057,7 +3074,7 @@ main(int argc, char *argv[]) /* process command-line options */ - while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", long_options, &option_index)) != -1) + while ((c = getopt_long(argc, argv, "dD:E:kL:m:nNU:WA:o:sST:X:x:", long_options, &option_index)) != -1) { switch (c) { @@ -3096,6 +3113,20 @@ main(int argc, char *argv[]) debug = true; printf(_("Running in debug mode.\n")); break; + case 'm': + if (sscanf(optarg, XID_FMT, &start_mx_id) != 1) + { + fprintf(stderr, "%s: invalid decimal START_MX_ID value\n", + progname); + exit(1); + } + if (!StartMultiXactIdIsValid(start_mx_id)) + { + fprintf(stderr, "%s: out-of-range START_MX_ID value (the value must be less than 2^62)\n", + progname); + exit(1); + } + break; case 'n': noclean = true; printf(_("Running in no-clean mode. Mistakes will not be cleaned up.\n")); @@ -3103,6 +3134,20 @@ main(int argc, char *argv[]) case 'N': do_sync = false; break; + case 'o': + if (sscanf(optarg, XID_FMT, &start_mx_offset) != 1) + { + fprintf(stderr, "%s: invalid decimal START_MX_OFFSET value\n", + progname); + exit(1); + } + if (!StartMultiXactOffsetIsValid(start_mx_offset)) + { + fprintf(stderr, "%s: out-of-range START_MX_OFFSET value (the value must be less than 2^62)\n", + progname); + exit(1); + } + break; case 'S': sync_only = true; break; @@ -3148,6 +3193,20 @@ main(int argc, char *argv[]) case 'X': xlog_dir = pg_strdup(optarg); break; + case 'x': + if (sscanf(optarg, XID_FMT, &start_xid) != 1) + { + fprintf(stderr, "%s: invalid decimal START_XID value\n", + progname); + exit(1); + } + if (!StartTransactionIdIsValid(start_xid)) + { + fprintf(stderr, "%s: out-of-range START_XID value (the value must be less than 2^62)\n", + progname); + exit(1); + } + break; case 12: str_wal_segment_size_mb = pg_strdup(optarg); break; diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 3c9d3401df..69978958b4 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -131,6 +131,14 @@ typedef enum WalLevel extern PGDLLIMPORT int wal_level; +/* + * these parameters specifies starting xid, multixact id and multixact offset + * for testing 64 bit xids + */ +extern TransactionId start_xid; +extern MultiXactId start_mx_id; +extern MultiXactOffset start_mx_offset; + /* Is WAL archiving enabled (always or only while server is running normally)? */ #define XLogArchivingActive() \ (AssertMacro(XLogArchiveMode == ARCHIVE_MODE_OFF || wal_level >= WAL_LEVEL_REPLICA), XLogArchiveMode > ARCHIVE_MODE_OFF) diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index 80f68df246..879f6a9bbe 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -410,6 +410,7 @@ sub init mkdir $self->archive_dir; TestLib::system_or_bail('initdb', '-D', $pgdata, '-A', 'trust', '-N', + '-x', '1249835483136', '-m', '2422361554944', '-o', '3594887626752', @{ $params{extra} }); TestLib::system_or_bail($ENV{PG_REGRESS}, '--config-auth', $pgdata); diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c index a1ee1041b4..e075551390 100644 --- a/src/test/regress/pg_regress.c +++ b/src/test/regress/pg_regress.c @@ -2275,7 +2275,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc /* initdb */ header(_("initializing database system")); snprintf(buf, sizeof(buf), - "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync%s%s > \"%s/log/initdb.log\" 2>&1", + "\"%s%sinitdb\" -D \"%s/data\" -x 1249835483136 -m 2422361554944 -o 3594887626752 --no-clean --no-sync%s%s > \"%s/log/initdb.log\" 2>&1", bindir ? bindir : "", bindir ? "/" : "", temp_instance,