diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml
new file mode 100644
index 6efb2e4..e4b1a04
*** a/doc/src/sgml/ref/initdb.sgml
--- b/doc/src/sgml/ref/initdb.sgml
*************** PostgreSQL documentation
*** 376,381 ****
--- 376,420 ----
+ 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
new file mode 100644
index 6136ffc..281f237
*** a/src/backend/access/transam/clog.c
--- b/src/backend/access/transam/clog.c
*************** void
*** 462,467 ****
--- 462,470 ----
BootStrapCLOG(void)
{
int slotno;
+ int64 pageno;
+
+ pageno = TransactionIdToPage(ShmemVariableCache->nextXid);
LWLockAcquire(CLogControlLock, LW_EXCLUSIVE);
*************** BootStrapCLOG(void)
*** 472,477 ****
--- 475,490 ----
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
new file mode 100644
index a4b2c97..8e11a49
*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
*************** void
*** 1666,1671 ****
--- 1666,1673 ----
BootStrapMultiXact(void)
{
int slotno;
+ int64 multiOffsetPageno;
+ int64 multiMemberPageno;
LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
*************** BootStrapMultiXact(void)
*** 1676,1681 ****
--- 1678,1694 ----
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);
*************** BootStrapMultiXact(void)
*** 1687,1693 ****
--- 1700,1731 ----
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
new file mode 100644
index cc9eee6..8797a52
*** a/src/backend/access/transam/subtrans.c
--- b/src/backend/access/transam/subtrans.c
*************** void
*** 210,220 ****
BootStrapSUBTRANS(void)
{
int slotno;
LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);
/* Create and zero the first page of the subtrans log */
! slotno = ZeroSUBTRANSPage(0);
/* Make sure it's written out */
SimpleLruWritePage(SubTransCtl, slotno);
--- 210,223 ----
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(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
new file mode 100644
index 6c6e88e..b36f751
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
*************** int CommitDelay = 0; /* precommit dela
*** 106,111 ****
--- 106,115 ----
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
*************** BootStrapXLOG(void)
*** 5003,5012 ****
checkPoint.ThisTimeLineID = ThisTimeLineID;
checkPoint.PrevTimeLineID = ThisTimeLineID;
checkPoint.fullPageWrites = fullPageWrites;
! checkPoint.nextXid = FirstNormalTransactionId + 1;
checkPoint.nextOid = FirstBootstrapObjectId;
! checkPoint.nextMulti = FirstMultiXactId + 1;
! checkPoint.nextMultiOffset = 0;
checkPoint.oldestXid = checkPoint.nextXid - 1;
checkPoint.oldestXidDB = TemplateDbOid;
checkPoint.oldestMulti = checkPoint.nextMulti - 1;
--- 5007,5016 ----
checkPoint.ThisTimeLineID = ThisTimeLineID;
checkPoint.PrevTimeLineID = ThisTimeLineID;
checkPoint.fullPageWrites = fullPageWrites;
! checkPoint.nextXid = Max(FirstNormalTransactionId + 1, start_xid);
checkPoint.nextOid = FirstBootstrapObjectId;
! checkPoint.nextMulti = Max(FirstMultiXactId + 1, start_mx_id);
! checkPoint.nextMultiOffset = start_mx_offset;
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
new file mode 100644
index 9fd692b..394e3a3
*** a/src/backend/bootstrap/bootstrap.c
--- b/src/backend/bootstrap/bootstrap.c
*************** AuxiliaryProcessMain(int argc, char *arg
*** 222,228 ****
/* If no -x argument, we are a CheckerProcess */
MyAuxProcType = CheckerProcess;
! while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:x:-:")) != -1)
{
switch (flag)
{
--- 222,231 ----
/* If no -x argument, we are a CheckerProcess */
MyAuxProcType = CheckerProcess;
! start_xid = 0;
! start_mx_id = 0;
! start_mx_offset = 0;
! while ((flag = getopt(argc, argv, "B:c:d:D:Fkm:o:r:X:x:-:")) != -1)
{
switch (flag)
{
*************** AuxiliaryProcessMain(int argc, char *arg
*** 251,259 ****
--- 254,283 ----
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 'X':
+ 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
new file mode 100644
index cd2f4b6..5851ddf
*** a/src/bin/initdb/initdb.c
--- b/src/bin/initdb/initdb.c
*************** static bool sync_only = false;
*** 141,146 ****
--- 141,149 ----
static bool show_setting = false;
static bool data_checksums = false;
static char *xlog_dir = "";
+ static TransactionId start_xid = 0;
+ static MultiXactId start_mx_id = 0;
+ static MultiXactOffset start_mx_offset = 0;
/* internal vars */
*************** bootstrap_template1(void)
*** 1356,1364 ****
unsetenv("PGCLIENTENCODING");
snprintf(cmd, sizeof(cmd),
! "\"%s\" --boot -x1 %s %s %s",
backend_exec,
data_checksums ? "-k" : "",
boot_options, talkargs);
PG_CMD_OPEN;
--- 1359,1370 ----
unsetenv("PGCLIENTENCODING");
snprintf(cmd, sizeof(cmd),
! "\"%s\" --boot -x1 %s %s " XID_FMT " %s " XID_FMT " %s " XID_FMT " %s %s",
backend_exec,
data_checksums ? "-k" : "",
+ "-X", start_xid,
+ "-m", start_mx_id,
+ "-o", start_mx_offset,
boot_options, talkargs);
PG_CMD_OPEN;
*************** usage(const char *progname)
*** 2272,2287 ****
printf(_(" --no-locale equivalent to --locale=C\n"));
printf(_(" --pwfile=FILE read password for the new superuser from file\n"));
printf(_(" -T, --text-search-config=CFG\n"
! " default text search configuration\n"));
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(_("\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(_(" -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(_(" -s, --show show internal settings\n"));
printf(_(" -S, --sync-only only sync data directory\n"));
printf(_("\nOther options:\n"));
--- 2278,2301 ----
printf(_(" --no-locale equivalent to --locale=C\n"));
printf(_(" --pwfile=FILE read password for the new superuser from file\n"));
printf(_(" -T, --text-search-config=CFG\n"
! " default text search configuration\n"));
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(_("\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"));
*************** main(int argc, char *argv[])
*** 2965,2970 ****
--- 2979,2987 ----
{"no-sync", no_argument, NULL, 'N'},
{"sync-only", no_argument, NULL, 'S'},
{"waldir", required_argument, NULL, 'X'},
+ {"xid", required_argument, NULL, 'x'},
+ {"multixact-id", required_argument, NULL, 'm'},
+ {"multixact-offset", required_argument, NULL, 'o'},
{"data-checksums", no_argument, NULL, 'k'},
{NULL, 0, NULL, 0}
};
*************** main(int argc, char *argv[])
*** 3007,3013 ****
/* process command-line options */
! while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", long_options, &option_index)) != -1)
{
switch (c)
{
--- 3024,3030 ----
/* process command-line options */
! while ((c = getopt_long(argc, argv, "dD:E:kL:m:nNU:WA:o:sST:X:x:", long_options, &option_index)) != -1)
{
switch (c)
{
*************** main(int argc, char *argv[])
*** 3046,3051 ****
--- 3063,3082 ----
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"));
*************** main(int argc, char *argv[])
*** 3053,3058 ****
--- 3084,3103 ----
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;
*************** main(int argc, char *argv[])
*** 3098,3103 ****
--- 3143,3162 ----
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;
default:
/* getopt_long already emitted a complaint */
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
new file mode 100644
index 41c2fde..981f898
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
*************** typedef enum WalLevel
*** 130,135 ****
--- 130,143 ----
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
new file mode 100644
index 42e66ed..b5be7fd
*** a/src/test/perl/PostgresNode.pm
--- b/src/test/perl/PostgresNode.pm
*************** sub init
*** 405,410 ****
--- 405,411 ----
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
new file mode 100644
index b685aeb..71a2058
*** a/src/test/regress/pg_regress.c
--- b/src/test/regress/pg_regress.c
*************** regression_main(int argc, char *argv[],
*** 2246,2252 ****
/* 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",
bindir ? bindir : "",
bindir ? "/" : "",
temp_instance,
--- 2246,2252 ----
/* initdb */
header(_("initializing database system"));
snprintf(buf, sizeof(buf),
! "\"%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,