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,