diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c new file mode 100644 index f8ac343..8b9abe5 *** a/contrib/pageinspect/heapfuncs.c --- b/contrib/pageinspect/heapfuncs.c *************** *** 32,37 **** --- 32,39 ---- #include "utils/array.h" #include "utils/builtins.h" #include "utils/rel.h" + #include "access/multixact.h" + #include "access/transam.h" /* *************** tuple_data_split(PG_FUNCTION_ARGS) *** 476,478 **** --- 478,520 ---- PG_RETURN_ARRAYTYPE_P(res); } + + 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.5.sql b/contrib/pageinspect/pageinspect--1.5.sql new file mode 100644 index 1e40c3c..9f936e4 *** a/contrib/pageinspect/pageinspect--1.5.sql --- b/contrib/pageinspect/pageinspect--1.5.sql *************** CREATE FUNCTION gin_leafpage_items(IN pa *** 277,279 **** --- 277,284 ---- RETURNS SETOF record AS 'MODULE_PATHNAME', 'gin_leafpage_items' LANGUAGE C STRICT PARALLEL SAFE; + + 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 b019bc1..56ddb79 *** a/src/backend/access/heap/heapam.c --- b/src/backend/access/heap/heapam.c *************** FreezeMultiXactId(MultiXactId multi, uin *** 6552,6558 **** * 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; } --- 6552,6558 ---- * 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 e9588a7..9bfce79 *** a/src/backend/access/transam/multixact.c --- b/src/backend/access/transam/multixact.c *************** MultiXactIdCreate(TransactionId xid1, Mu *** 406,412 **** members[1].xid = xid2; members[1].status = status2; ! newMulti = MultiXactIdCreateFromMembers(2, members); debug_elog3(DEBUG2, "Create: %s", mxid_to_string(newMulti, 2, members)); --- 406,412 ---- 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 *** 472,478 **** */ member.xid = xid; member.status = status; ! newMulti = MultiXactIdCreateFromMembers(1, &member); debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u", multi, newMulti); --- 472,478 ---- */ 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 *** 524,530 **** newMembers[j].xid = xid; newMembers[j++].status = status; ! newMulti = MultiXactIdCreateFromMembers(j, newMembers); pfree(members); pfree(newMembers); --- 524,530 ---- newMembers[j].xid = xid; newMembers[j++].status = status; ! newMulti = MultiXactIdCreateFromMembers(j, newMembers, false); pfree(members); pfree(newMembers); *************** ReadNextMultiXactId(void) *** 743,749 **** * NB: the passed members[] array will be sorted in-place. */ MultiXactId ! MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members) { MultiXactId multi; MultiXactOffset offset; --- 743,749 ---- * 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 *** 762,768 **** * 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!"); --- 762,770 ---- * 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 ab5de62..d13cf74 *** a/src/include/access/multixact.h --- b/src/include/access/multixact.h *************** typedef struct xl_multixact_truncate *** 102,111 **** 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, bool isLockOnly); --- 102,112 ---- 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, bool isLockOnly);