*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
***************
*** 72,77 ****
--- 72,78 ----
  #include "catalog/pg_type.h"
  #include "commands/dbcommands.h"
  #include "funcapi.h"
+ #include "lib/ilist.h"
  #include "miscadmin.h"
  #include "pg_trace.h"
  #include "postmaster/autovacuum.h"
***************
*** 262,274 **** static MultiXactId *OldestVisibleMXactId;
   */
  typedef struct mXactCacheEnt
  {
- 	struct mXactCacheEnt *next;
  	MultiXactId multi;
  	int			nmembers;
  	MultiXactMember members[FLEXIBLE_ARRAY_MEMBER];
  } mXactCacheEnt;
  
! static mXactCacheEnt *MXactCache = NULL;
  static MemoryContext MXactContext = NULL;
  
  #ifdef MULTIXACT_DEBUG
--- 263,277 ----
   */
  typedef struct mXactCacheEnt
  {
  	MultiXactId multi;
  	int			nmembers;
+ 	dlist_node	node;
  	MultiXactMember members[FLEXIBLE_ARRAY_MEMBER];
  } mXactCacheEnt;
  
! #define MAX_CACHE_ENTRIES	256
! static dlist_head	MXactCache = DLIST_STATIC_INIT(MXactCache);
! static int			MXactCacheMembers = 0;
  static MemoryContext MXactContext = NULL;
  
  #ifdef MULTIXACT_DEBUG
***************
*** 1306,1312 **** mxactMemberComparator(const void *arg1, const void *arg2)
  static MultiXactId
  mXactCacheGetBySet(int nmembers, MultiXactMember *members)
  {
! 	mXactCacheEnt *entry;
  
  	debug_elog3(DEBUG2, "CacheGet: looking for %s",
  				mxid_to_string(InvalidMultiXactId, nmembers, members));
--- 1309,1315 ----
  static MultiXactId
  mXactCacheGetBySet(int nmembers, MultiXactMember *members)
  {
! 	dlist_iter	iter;
  
  	debug_elog3(DEBUG2, "CacheGet: looking for %s",
  				mxid_to_string(InvalidMultiXactId, nmembers, members));
***************
*** 1314,1321 **** mXactCacheGetBySet(int nmembers, MultiXactMember *members)
  	/* sort the array so comparison is easy */
  	qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
  
! 	for (entry = MXactCache; entry != NULL; entry = entry->next)
  	{
  		if (entry->nmembers != nmembers)
  			continue;
  
--- 1317,1326 ----
  	/* sort the array so comparison is easy */
  	qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
  
! 	dlist_foreach(iter, &MXactCache)
  	{
+ 		mXactCacheEnt *entry = dlist_container(mXactCacheEnt, node, iter.cur);
+ 
  		if (entry->nmembers != nmembers)
  			continue;
  
***************
*** 1326,1331 **** mXactCacheGetBySet(int nmembers, MultiXactMember *members)
--- 1331,1337 ----
  		if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
  		{
  			debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
+ 			dlist_move_head(&MXactCache, iter.cur);
  			return entry->multi;
  		}
  	}
***************
*** 1345,1356 **** mXactCacheGetBySet(int nmembers, MultiXactMember *members)
  static int
  mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
  {
! 	mXactCacheEnt *entry;
  
  	debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
  
! 	for (entry = MXactCache; entry != NULL; entry = entry->next)
  	{
  		if (entry->multi == multi)
  		{
  			MultiXactMember *ptr;
--- 1351,1364 ----
  static int
  mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
  {
! 	dlist_iter	iter;
  
  	debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
  
! 	dlist_foreach(iter, &MXactCache)
  	{
+ 		mXactCacheEnt *entry = dlist_container(mXactCacheEnt, node, iter.cur);
+ 
  		if (entry->multi == multi)
  		{
  			MultiXactMember *ptr;
***************
*** 1366,1371 **** mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
--- 1374,1382 ----
  						mxid_to_string(multi,
  									   entry->nmembers,
  									   entry->members));
+ 
+ 			dlist_move_head(&MXactCache, iter.cur);
+ 
  			return entry->nmembers;
  		}
  	}
***************
*** 1409,1416 **** mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
  	/* mXactCacheGetBySet assumes the entries are sorted, so sort them */
  	qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
  
! 	entry->next = MXactCache;
! 	MXactCache = entry;
  }
  
  static char *
--- 1420,1435 ----
  	/* mXactCacheGetBySet assumes the entries are sorted, so sort them */
  	qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
  
! 	dlist_push_head(&MXactCache, &entry->node);
! 	if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES)
! 	{
! 		dlist_node *node;
! 
! 		node = dlist_tail_node(&MXactCache);
! 		dlist_delete(dlist_tail_node(&MXactCache));
! 		MXactCacheMembers--;
! 		pfree(dlist_container(mXactCacheEnt, node, node));
! 	}
  }
  
  static char *
***************
*** 1485,1491 **** AtEOXact_MultiXact(void)
  	 * a child of TopTransactionContext, we needn't delete it explicitly.
  	 */
  	MXactContext = NULL;
! 	MXactCache = NULL;
  }
  
  /*
--- 1504,1511 ----
  	 * a child of TopTransactionContext, we needn't delete it explicitly.
  	 */
  	MXactContext = NULL;
! 	dlist_init(&MXactCache);
! 	MXactCacheMembers = 0;
  }
  
  /*
***************
*** 1551,1557 **** PostPrepare_MultiXact(TransactionId xid)
  	 * Discard the local MultiXactId cache like in AtEOX_MultiXact
  	 */
  	MXactContext = NULL;
! 	MXactCache = NULL;
  }
  
  /*
--- 1571,1578 ----
  	 * Discard the local MultiXactId cache like in AtEOX_MultiXact
  	 */
  	MXactContext = NULL;
! 	dlist_init(&MXactCache);
! 	MXactCacheMembers = 0;
  }
  
  /*
