>From fdfd992ff907e75d4c1c009b9b191748678d5daf Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Thu, 12 Dec 2013 18:18:36 -0300
Subject: [PATCH 4/4] set the PROC_FREEZING_MULTI flag to avoid assert

---
 src/backend/access/heap/heapam.c       |   20 ++++++++++++++++----
 src/backend/access/transam/multixact.c |    9 +++++++--
 src/include/storage/proc.h             |    3 ++-
 3 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 9616c18..bf9300d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -60,6 +60,7 @@
 #include "storage/freespace.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
+#include "storage/proc.h"
 #include "storage/procarray.h"
 #include "storage/smgr.h"
 #include "storage/standby.h"
@@ -5520,8 +5521,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
  * WAL-log what we would need to do, and return TRUE.  Return FALSE if nothing
  * is to be changed.
  *
- * Caller is responsible for setting the offset field, if appropriate.	This
- * is only necessary if the freeze is to be WAL-logged.
+ * Caller is responsible for setting the offset field, if appropriate.
  *
  * It is assumed that the caller has checked the tuple with
  * HeapTupleSatisfiesVacuum() and determined that it is not HEAPTUPLE_DEAD
@@ -5587,8 +5587,20 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
 		TransactionId newxmax;
 		uint16		flags;
 
-		newxmax = FreezeMultiXactId(xid, tuple->t_infomask,
-									cutoff_xid, cutoff_multi, &flags);
+		PG_TRY();
+		{
+			/* set flag to let multixact.c know what we're doing */
+			MyPgXact->vacuumFlags |= PROC_FREEZING_MULTI;
+			newxmax = FreezeMultiXactId(xid, tuple->t_infomask,
+										cutoff_xid, cutoff_multi, &flags);
+		}
+		PG_CATCH();
+		{
+			MyPgXact->vacuumFlags &= ~PROC_FREEZING_MULTI;
+			PG_RE_THROW();
+		}
+		PG_END_TRY();
+		MyPgXact->vacuumFlags &= ~PROC_FREEZING_MULTI;
 
 		if (flags & FRM_INVALIDATE_XMAX)
 			freeze_xmax = true;
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index ed7101f..0166978 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -77,6 +77,7 @@
 #include "postmaster/autovacuum.h"
 #include "storage/lmgr.h"
 #include "storage/pmsignal.h"
+#include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/builtins.h"
 #include "utils/memutils.h"
@@ -864,8 +865,12 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
 
 	debug_elog3(DEBUG2, "GetNew: for %d xids", nmembers);
 
-	/* MultiXactIdSetOldestMember() must have been called already */
-	Assert(MultiXactIdIsValid(OldestMemberMXactId[MyBackendId]));
+	/*
+	 * MultiXactIdSetOldestMember() must have been called already, but don't
+	 * check while freezing MultiXactIds.
+	 */
+	Assert((MyPgXact->vacuumFlags & PROC_FREEZING_MULTI) ||
+		   MultiXactIdIsValid(OldestMemberMXactId[MyBackendId]));
 
 	/* safety check, we should never get this far in a HS slave */
 	if (RecoveryInProgress())
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 3b04d3c..7e53a3a 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -42,9 +42,10 @@ struct XidCache
 #define		PROC_IN_VACUUM		0x02	/* currently running lazy vacuum */
 #define		PROC_IN_ANALYZE		0x04	/* currently running analyze */
 #define		PROC_VACUUM_FOR_WRAPAROUND 0x08		/* set by autovac only */
+#define		PROC_FREEZING_MULTI	0x10	/* set while freezing multis */
 
 /* flags reset at EOXact */
-#define		PROC_VACUUM_STATE_MASK (0x0E)
+#define		PROC_VACUUM_STATE_MASK (0x1E)
 
 /*
  * We allow a small number of "weak" relation locks (AccesShareLock,
-- 
1.7.10.4

