commit b7538e5da55eb8e69021ccb2c7bca0d0019be6c3
Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date:   Tue Apr 28 19:15:02 2015 -0300

    fix boot after pg_upgrade

diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 06bcd52..6e0e870 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1042,9 +1042,9 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
 	ExtendMultiXactOffset(result);
 
 	/*
-	 * Reserve the members space, similarly to above.  Also, be careful not to
-	 * return zero as the starting offset for any multixact. See
-	 * GetMultiXactIdMembers() for motivation.
+	 * Compute the members space we need.  Be careful not to return zero as the
+	 * starting offset for any multixact.  See GetMultiXactIdMembers() for
+	 * motivation.
 	 */
 	nextOffset = MultiXactState->nextOffset;
 	if (nextOffset == 0)
@@ -1096,6 +1096,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
 					MultiXactState->offsetStopLimit - nextOffset + nmembers),
 				 errhint("Execute a database-wide VACUUM in that database with reduced vacuum_multixact_freeze_min_age and vacuum_multixact_freeze_table_age settings.")));
 
+	/* And make sure there is room in the members files */
 	ExtendMultiXactMember(nextOffset, nmembers);
 
 	/*
@@ -1938,6 +1939,17 @@ MaybeExtendOffsetSlru(void)
 	}
 
 	LWLockRelease(MultiXactOffsetControlLock);
+
+	/* also create member page 0, also removed by pg_upgrade */
+	LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
+	if (!SimpleLruDoesPhysicalPageExist(MultiXactMemberCtl, 0))
+	{
+		int		slotno;
+
+		slotno = ZeroMultiXactMemberPage(0, false);
+		SimpleLruWritePage(MultiXactMemberCtl, slotno);
+	}
+	LWLockRelease(MultiXactMemberControlLock);
 }
 
 /*
@@ -1966,12 +1978,6 @@ StartupMultiXact(void)
 	 */
 	pageno = MXOffsetToMemberPage(offset);
 	MultiXactMemberCtl->shared->latest_page_number = pageno;
-
-	/*
-	 * compute the oldest member we need to keep around to avoid old member
-	 * data overrun.
-	 */
-	DetermineSafeOldestOffset(MultiXactState->oldestMultiXactId);
 }
 
 /*
@@ -2145,7 +2151,8 @@ MultiXactSetNextMXact(MultiXactId nextMulti,
  * of our cluster), and the OID of the (or a) database with that value.
  */
 void
-SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
+SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid,
+					bool compute_offset_limit)
 {
 	MultiXactId multiVacLimit;
 	MultiXactId multiWarnLimit;
@@ -2217,7 +2224,8 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
 	curMulti = MultiXactState->nextMXact;
 	LWLockRelease(MultiXactGenLock);
 
-	DetermineSafeOldestOffset(oldest_datminmxid);
+	if (compute_offset_limit)
+		DetermineSafeOldestOffset(oldest_datminmxid);
 
 	/* Log the info */
 	ereport(DEBUG1,
@@ -2312,7 +2320,7 @@ void
 MultiXactAdvanceOldest(MultiXactId oldestMulti, Oid oldestMultiDB)
 {
 	if (MultiXactIdPrecedes(MultiXactState->oldestMultiXactId, oldestMulti))
-		SetMultiXactIdLimit(oldestMulti, oldestMultiDB);
+		SetMultiXactIdLimit(oldestMulti, oldestMultiDB, true);
 	else
 		DetermineSafeOldestOffset(oldestMulti);
 }
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c52f94c..ba2f236 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -4061,7 +4061,7 @@ BootStrapXLOG(void)
 	ShmemVariableCache->oidCount = 0;
 	MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset);
 	SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
-	SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB);
+	SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB, false);
 
 	/* Set up the XLOG page header */
 	page->xlp_magic = XLOG_PAGE_MAGIC;
@@ -5290,7 +5290,7 @@ StartupXLOG(void)
 	ShmemVariableCache->oidCount = 0;
 	MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset);
 	SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
-	SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB);
+	SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB, false);
 	MultiXactSetSafeTruncate(checkPoint.oldestMulti);
 	XLogCtl->ckptXidEpoch = checkPoint.nextXidEpoch;
 	XLogCtl->ckptXid = checkPoint.nextXid;
@@ -8133,7 +8133,7 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
 		MultiXactSetNextMXact(checkPoint.nextMulti,
 							  checkPoint.nextMultiOffset);
 		SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB);
-		SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB);
+		SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB, true);
 		MultiXactSetSafeTruncate(checkPoint.oldestMulti);
 
 		/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index ba3fbbd..746a093 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -1093,7 +1093,7 @@ vac_truncate_clog(TransactionId frozenXID,
 	 * signalling twice?
 	 */
 	SetTransactionIdLimit(frozenXID, oldestxid_datoid);
-	SetMultiXactIdLimit(minMulti, minmulti_datoid);
+	SetMultiXactIdLimit(minMulti, minmulti_datoid, true);
 }
 
 
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index e69a3d2..3ad8d16 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -111,7 +111,7 @@ extern void StartupMultiXact(void);
 extern void TrimMultiXact(void);
 extern void ShutdownMultiXact(void);
 extern void SetMultiXactIdLimit(MultiXactId oldest_datminmxid,
-					Oid oldest_datoid);
+					Oid oldest_datoid, bool compute_offset_limit);
 extern void MultiXactGetCheckptMulti(bool is_shutdown,
 						 MultiXactId *nextMulti,
 						 MultiXactOffset *nextMultiOffset,
