From b264bfe61b315a5f65d72b9550592cc9f73bf0a8 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Tue, 31 Dec 2013 00:42:11 -0300
Subject: [PATCH 1/3] pg_burn_multixact utility

Andres Freund, minor tweaks by me

(And then updated by Jeff to apply to pageinspect 1.2)

diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c
new file mode 100644
index dedc8fe..7903b35
*** a/contrib/pageinspect/heapfuncs.c
--- b/contrib/pageinspect/heapfuncs.c
***************
*** 29,34 ****
--- 29,36 ----
  #include "funcapi.h"
  #include "utils/builtins.h"
  #include "miscadmin.h"
+ #include "access/multixact.h"
+ #include "access/transam.h"
  
  
  /*
*************** heap_page_items(PG_FUNCTION_ARGS)
*** 222,224 ****
--- 224,266 ----
  	else
  		SRF_RETURN_DONE(fctx);
  }
+ 
+ extern Datum
+ pg_burn_multixact(PG_FUNCTION_ARGS);
+ PG_FUNCTION_INFO_V1(pg_burn_multixact);
+ 
+ Datum
+ pg_burn_multixact(PG_FUNCTION_ARGS)
+ {
+ 	int		rep = PG_GETARG_INT32(0);
+ 	int		size = PG_GETARG_INT32(1);
+ 	MultiXactMember *members;
+ 	MultiXactId ret;
+ 	TransactionId id = ReadNewTransactionId() - size;
+ 	int		i;
+ 
+ 	if (rep < 1)
+ 		elog(ERROR, "need to burn, burn, burn");
+ 
+ 	members = palloc(size * sizeof(MultiXactMember));
+ 	for (i = 0; i < size; i++)
+ 	{
+ 		members[i].xid = id++;
+ 		members[i].status = MultiXactStatusForShare;
+ 
+ 		if (!TransactionIdIsNormal(members[i].xid))
+ 		{
+ 			id = FirstNormalTransactionId;
+ 			members[i].xid = id++;
+ 		}
+ 	}
+ 
+ 	MultiXactIdSetOldestMember();
+ 
+ 	for (i = 0; i < rep; i++)
+ 	{
+ 		ret = MultiXactIdCreateFromMembers(size, members, true);
+ 	}
+ 
+ 	PG_RETURN_INT64((int64) ret);
+ }
diff --git a/contrib/pageinspect/pageinspect--1.2.sql b/contrib/pageinspect/pageinspect--1.2.sql
new file mode 100644
index 15e8e1e..f0aeecf
*** a/contrib/pageinspect/pageinspect--1.2.sql
--- b/contrib/pageinspect/pageinspect--1.2.sql
*************** CREATE FUNCTION fsm_page_contents(IN pag
*** 105,107 ****
--- 105,112 ----
  RETURNS text
  AS 'MODULE_PATHNAME', 'fsm_page_contents'
  LANGUAGE C STRICT;
+ 
+ CREATE FUNCTION pg_burn_multixact(num int4, size int4)
+ RETURNS int4
+ AS 'MODULE_PATHNAME', 'pg_burn_multixact'
+ LANGUAGE C STRICT;
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
new file mode 100644
index b77c32c..cdd59fa
*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
*************** FreezeMultiXactId(MultiXactId multi, uin
*** 5714,5720 ****
  		 * Create a new multixact with the surviving members of the previous
  		 * one, to set as new Xmax in the tuple.
  		 */
! 		xid = MultiXactIdCreateFromMembers(nnewmembers, newmembers);
  		*flags |= FRM_RETURN_IS_MULTI;
  	}
  
--- 5714,5720 ----
  		 * Create a new multixact with the surviving members of the previous
  		 * one, to set as new Xmax in the tuple.
  		 */
! 		xid = MultiXactIdCreateFromMembers(nnewmembers, newmembers, false);
  		*flags |= FRM_RETURN_IS_MULTI;
  	}
  
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
new file mode 100644
index 9da22c8..86ed386
*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
*************** MultiXactIdCreate(TransactionId xid1, Mu
*** 349,355 ****
  	members[1].xid = xid2;
  	members[1].status = status2;
  
! 	newMulti = MultiXactIdCreateFromMembers(2, members);
  
  	debug_elog3(DEBUG2, "Create: %s",
  				mxid_to_string(newMulti, 2, members));
--- 349,355 ----
  	members[1].xid = xid2;
  	members[1].status = status2;
  
! 	newMulti = MultiXactIdCreateFromMembers(2, members, false);
  
  	debug_elog3(DEBUG2, "Create: %s",
  				mxid_to_string(newMulti, 2, members));
*************** MultiXactIdExpand(MultiXactId multi, Tra
*** 415,421 ****
  		 */
  		member.xid = xid;
  		member.status = status;
! 		newMulti = MultiXactIdCreateFromMembers(1, &member);
  
  		debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
  					multi, newMulti);
--- 415,421 ----
  		 */
  		member.xid = xid;
  		member.status = status;
! 		newMulti = MultiXactIdCreateFromMembers(1, &member, false);
  
  		debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
  					multi, newMulti);
*************** MultiXactIdExpand(MultiXactId multi, Tra
*** 467,473 ****
  
  	newMembers[j].xid = xid;
  	newMembers[j++].status = status;
! 	newMulti = MultiXactIdCreateFromMembers(j, newMembers);
  
  	pfree(members);
  	pfree(newMembers);
--- 467,473 ----
  
  	newMembers[j].xid = xid;
  	newMembers[j++].status = status;
! 	newMulti = MultiXactIdCreateFromMembers(j, newMembers, false);
  
  	pfree(members);
  	pfree(newMembers);
*************** ReadNextMultiXactId(void)
*** 686,692 ****
   * NB: the passed members[] array will be sorted in-place.
   */
  MultiXactId
! MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
  {
  	MultiXactId multi;
  	MultiXactOffset offset;
--- 686,692 ----
   * NB: the passed members[] array will be sorted in-place.
   */
  MultiXactId
! MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members, bool nocache)
  {
  	MultiXactId multi;
  	MultiXactOffset offset;
*************** MultiXactIdCreateFromMembers(int nmember
*** 706,712 ****
  	 * corner cases where someone else added us to a MultiXact without our
  	 * knowledge, but it's not worth checking for.)
  	 */
! 	multi = mXactCacheGetBySet(nmembers, members);
  	if (MultiXactIdIsValid(multi))
  	{
  		debug_elog2(DEBUG2, "Create: in cache!");
--- 706,714 ----
  	 * corner cases where someone else added us to a MultiXact without our
  	 * knowledge, but it's not worth checking for.)
  	 */
! 	multi = nocache ? InvalidMultiXactId :
! 		mXactCacheGetBySet(nmembers, members);
! 
  	if (MultiXactIdIsValid(multi))
  	{
  		debug_elog2(DEBUG2, "Create: in cache!");
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
new file mode 100644
index 1f048e8..0fe5390
*** a/src/include/access/multixact.h
--- b/src/include/access/multixact.h
*************** typedef struct xl_multixact_create
*** 83,92 ****
  extern MultiXactId MultiXactIdCreate(TransactionId xid1,
  				  MultiXactStatus status1, TransactionId xid2,
  				  MultiXactStatus status2);
  extern MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid,
  				  MultiXactStatus status);
  extern MultiXactId MultiXactIdCreateFromMembers(int nmembers,
! 							 MultiXactMember *members);
  
  extern MultiXactId ReadNextMultiXactId(void);
  extern bool MultiXactIdIsRunning(MultiXactId multi);
--- 83,93 ----
  extern MultiXactId MultiXactIdCreate(TransactionId xid1,
  				  MultiXactStatus status1, TransactionId xid2,
  				  MultiXactStatus status2);
+ extern MultiXactId CreateMultiXactId(int nmembers, MultiXactMember *members, bool nocache);
  extern MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid,
  				  MultiXactStatus status);
  extern MultiXactId MultiXactIdCreateFromMembers(int nmembers,
! 							 MultiXactMember *members, bool nocache);
  
  extern MultiXactId ReadNextMultiXactId(void);
  extern bool MultiXactIdIsRunning(MultiXactId multi);
