PostgreSQL Source Code  git master
multixact.h File Reference
#include "access/xlogreader.h"
#include "lib/stringinfo.h"
#include "storage/sync.h"
Include dependency graph for multixact.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  MultiXactMember
 
struct  xl_multixact_create
 
struct  xl_multixact_truncate
 

Macros

#define InvalidMultiXactId   ((MultiXactId) 0)
 
#define FirstMultiXactId   ((MultiXactId) 1)
 
#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)
 
#define MultiXactIdIsValid(multi)   ((multi) != InvalidMultiXactId)
 
#define MaxMultiXactOffset   ((MultiXactOffset) 0xFFFFFFFF)
 
#define NUM_MULTIXACTOFFSET_BUFFERS   8
 
#define NUM_MULTIXACTMEMBER_BUFFERS   16
 
#define MaxMultiXactStatus   MultiXactStatusUpdate
 
#define ISUPDATE_from_mxstatus(status)    ((status) > MultiXactStatusForUpdate)
 
#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00
 
#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10
 
#define XLOG_MULTIXACT_CREATE_ID   0x20
 
#define XLOG_MULTIXACT_TRUNCATE_ID   0x30
 
#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))
 
#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))
 

Typedefs

typedef struct MultiXactMember MultiXactMember
 
typedef struct xl_multixact_create xl_multixact_create
 
typedef struct xl_multixact_truncate xl_multixact_truncate
 

Enumerations

enum  MultiXactStatus {
  MultiXactStatusForKeyShare = 0x00 , MultiXactStatusForShare = 0x01 , MultiXactStatusForNoKeyUpdate = 0x02 , MultiXactStatusForUpdate = 0x03 ,
  MultiXactStatusNoKeyUpdate = 0x04 , MultiXactStatusUpdate = 0x05
}
 

Functions

MultiXactId MultiXactIdCreate (TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
 
MultiXactId MultiXactIdExpand (MultiXactId multi, TransactionId xid, MultiXactStatus status)
 
MultiXactId MultiXactIdCreateFromMembers (int nmembers, MultiXactMember *members)
 
MultiXactId ReadNextMultiXactId (void)
 
void ReadMultiXactIdRange (MultiXactId *oldest, MultiXactId *next)
 
bool MultiXactIdIsRunning (MultiXactId multi, bool isLockOnly)
 
void MultiXactIdSetOldestMember (void)
 
int GetMultiXactIdMembers (MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
 
bool MultiXactIdPrecedes (MultiXactId multi1, MultiXactId multi2)
 
bool MultiXactIdPrecedesOrEquals (MultiXactId multi1, MultiXactId multi2)
 
int multixactoffsetssyncfiletag (const FileTag *ftag, char *path)
 
int multixactmemberssyncfiletag (const FileTag *ftag, char *path)
 
void AtEOXact_MultiXact (void)
 
void AtPrepare_MultiXact (void)
 
void PostPrepare_MultiXact (TransactionId xid)
 
Size MultiXactShmemSize (void)
 
void MultiXactShmemInit (void)
 
void BootStrapMultiXact (void)
 
void StartupMultiXact (void)
 
void TrimMultiXact (void)
 
void SetMultiXactIdLimit (MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
 
void MultiXactGetCheckptMulti (bool is_shutdown, MultiXactId *nextMulti, MultiXactOffset *nextMultiOffset, MultiXactId *oldestMulti, Oid *oldestMultiDB)
 
void CheckPointMultiXact (void)
 
MultiXactId GetOldestMultiXactId (void)
 
void TruncateMultiXact (MultiXactId newOldestMulti, Oid newOldestMultiDB)
 
void MultiXactSetNextMXact (MultiXactId nextMulti, MultiXactOffset nextMultiOffset)
 
void MultiXactAdvanceNextMXact (MultiXactId minMulti, MultiXactOffset minMultiOffset)
 
void MultiXactAdvanceOldest (MultiXactId oldestMulti, Oid oldestMultiDB)
 
int MultiXactMemberFreezeThreshold (void)
 
void multixact_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postcommit (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postabort (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_redo (XLogReaderState *record)
 
void multixact_desc (StringInfo buf, XLogReaderState *record)
 
const char * multixact_identify (uint8 info)
 
char * mxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)
 

Macro Definition Documentation

◆ FirstMultiXactId

#define FirstMultiXactId   ((MultiXactId) 1)

Definition at line 25 of file multixact.h.

◆ InvalidMultiXactId

#define InvalidMultiXactId   ((MultiXactId) 0)

Definition at line 24 of file multixact.h.

◆ ISUPDATE_from_mxstatus

#define ISUPDATE_from_mxstatus (   status)     ((status) > MultiXactStatusForUpdate)

Definition at line 56 of file multixact.h.

◆ MaxMultiXactId

#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)

Definition at line 26 of file multixact.h.

◆ MaxMultiXactOffset

#define MaxMultiXactOffset   ((MultiXactOffset) 0xFFFFFFFF)

Definition at line 30 of file multixact.h.

◆ MaxMultiXactStatus

#define MaxMultiXactStatus   MultiXactStatusUpdate

Definition at line 53 of file multixact.h.

◆ MultiXactIdIsValid

#define MultiXactIdIsValid (   multi)    ((multi) != InvalidMultiXactId)

Definition at line 28 of file multixact.h.

◆ NUM_MULTIXACTMEMBER_BUFFERS

#define NUM_MULTIXACTMEMBER_BUFFERS   16

Definition at line 34 of file multixact.h.

◆ NUM_MULTIXACTOFFSET_BUFFERS

#define NUM_MULTIXACTOFFSET_BUFFERS   8

Definition at line 33 of file multixact.h.

◆ SizeOfMultiXactCreate

#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Definition at line 85 of file multixact.h.

◆ SizeOfMultiXactTruncate

#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))

Definition at line 100 of file multixact.h.

◆ XLOG_MULTIXACT_CREATE_ID

#define XLOG_MULTIXACT_CREATE_ID   0x20

Definition at line 74 of file multixact.h.

◆ XLOG_MULTIXACT_TRUNCATE_ID

#define XLOG_MULTIXACT_TRUNCATE_ID   0x30

Definition at line 75 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_MEM_PAGE

#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10

Definition at line 73 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_OFF_PAGE

#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00

Definition at line 72 of file multixact.h.

Typedef Documentation

◆ MultiXactMember

◆ xl_multixact_create

◆ xl_multixact_truncate

Enumeration Type Documentation

◆ MultiXactStatus

Enumerator
MultiXactStatusForKeyShare 
MultiXactStatusForShare 
MultiXactStatusForNoKeyUpdate 
MultiXactStatusForUpdate 
MultiXactStatusNoKeyUpdate 
MultiXactStatusUpdate 

Definition at line 41 of file multixact.h.

42 {
47  /* an update that doesn't touch "key" columns */
49  /* other updates, and delete */
50  MultiXactStatusUpdate = 0x05,
MultiXactStatus
Definition: multixact.h:42
@ MultiXactStatusForShare
Definition: multixact.h:44
@ MultiXactStatusForNoKeyUpdate
Definition: multixact.h:45
@ MultiXactStatusNoKeyUpdate
Definition: multixact.h:48
@ MultiXactStatusUpdate
Definition: multixact.h:50
@ MultiXactStatusForUpdate
Definition: multixact.h:46
@ MultiXactStatusForKeyShare
Definition: multixact.h:43

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1688 of file multixact.c.

1689 {
1690  /*
1691  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1692  * which should only be valid while within a transaction.
1693  *
1694  * We assume that storing a MultiXactId is atomic and so we need not take
1695  * MultiXactGenLock to do this.
1696  */
1699 
1700  /*
1701  * Discard the local MultiXactId cache. Since MXactContext was created as
1702  * a child of TopTransactionContext, we needn't delete it explicitly.
1703  */
1704  MXactContext = NULL;
1706 }
BackendId MyBackendId
Definition: globals.c:86
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:325
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:295
static dclist_head MXactCache
Definition: multixact.c:324
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:294
#define InvalidMultiXactId
Definition: multixact.h:24

References dclist_init(), InvalidMultiXactId, MXactCache, MXactContext, MyBackendId, OldestMemberMXactId, and OldestVisibleMXactId.

Referenced by AbortTransaction(), and CommitTransaction().

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1716 of file multixact.c.

1717 {
1718  MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1719 
1720  if (MultiXactIdIsValid(myOldestMember))
1722  &myOldestMember, sizeof(MultiXactId));
1723 }
TransactionId MultiXactId
Definition: c.h:651
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1296
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27

References MultiXactIdIsValid, MyBackendId, OldestMemberMXactId, RegisterTwoPhaseRecord(), and TWOPHASE_RM_MULTIXACT_ID.

Referenced by PrepareTransaction().

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1896 of file multixact.c.

1897 {
1898  int slotno;
1899 
1900  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1901 
1902  /* Create and zero the first page of the offsets log */
1903  slotno = ZeroMultiXactOffsetPage(0, false);
1904 
1905  /* Make sure it's written out */
1907  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1908 
1909  LWLockRelease(MultiXactOffsetSLRULock);
1910 
1911  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
1912 
1913  /* Create and zero the first page of the members log */
1914  slotno = ZeroMultiXactMemberPage(0, false);
1915 
1916  /* Make sure it's written out */
1918  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1919 
1920  LWLockRelease(MultiXactMemberSLRULock);
1921 }
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_EXCLUSIVE
Definition: lwlock.h:116
static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
Definition: multixact.c:1949
#define MultiXactMemberCtl
Definition: multixact.c:191
#define MultiXactOffsetCtl
Definition: multixact.c:190
static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
Definition: multixact.c:1933
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:649

References Assert(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactMemberCtl, MultiXactOffsetCtl, SimpleLruWritePage(), ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

Referenced by BootStrapXLOG().

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2162 of file multixact.c.

2163 {
2164  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2165 
2166  /*
2167  * Write dirty MultiXact pages to disk. This may result in sync requests
2168  * queued for later handling by ProcessSyncRequests(), as part of the
2169  * checkpoint.
2170  */
2173 
2174  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2175 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1199

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ GetMultiXactIdMembers()

int GetMultiXactIdMembers ( MultiXactId  multi,
MultiXactMember **  members,
bool  from_pgupgrade,
bool  isLockOnly 
)

Definition at line 1225 of file multixact.c.

1227 {
1228  int64 pageno;
1229  int64 prev_pageno;
1230  int entryno;
1231  int slotno;
1232  MultiXactOffset *offptr;
1233  MultiXactOffset offset;
1234  int length;
1235  int truelength;
1236  int i;
1237  MultiXactId oldestMXact;
1238  MultiXactId nextMXact;
1239  MultiXactId tmpMXact;
1240  MultiXactOffset nextOffset;
1241  MultiXactMember *ptr;
1242 
1243  debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
1244 
1245  if (!MultiXactIdIsValid(multi) || from_pgupgrade)
1246  {
1247  *members = NULL;
1248  return -1;
1249  }
1250 
1251  /* See if the MultiXactId is in the local cache */
1252  length = mXactCacheGetById(multi, members);
1253  if (length >= 0)
1254  {
1255  debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
1256  mxid_to_string(multi, length, *members));
1257  return length;
1258  }
1259 
1260  /* Set our OldestVisibleMXactId[] entry if we didn't already */
1262 
1263  /*
1264  * If we know the multi is used only for locking and not for updates, then
1265  * we can skip checking if the value is older than our oldest visible
1266  * multi. It cannot possibly still be running.
1267  */
1268  if (isLockOnly &&
1270  {
1271  debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
1272  *members = NULL;
1273  return -1;
1274  }
1275 
1276  /*
1277  * We check known limits on MultiXact before resorting to the SLRU area.
1278  *
1279  * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
1280  * useful; it has already been removed, or will be removed shortly, by
1281  * truncation. If one is passed, an error is raised.
1282  *
1283  * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
1284  * implies undetected ID wraparound has occurred. This raises a hard
1285  * error.
1286  *
1287  * Shared lock is enough here since we aren't modifying any global state.
1288  * Acquire it just long enough to grab the current counter values. We may
1289  * need both nextMXact and nextOffset; see below.
1290  */
1291  LWLockAcquire(MultiXactGenLock, LW_SHARED);
1292 
1293  oldestMXact = MultiXactState->oldestMultiXactId;
1294  nextMXact = MultiXactState->nextMXact;
1295  nextOffset = MultiXactState->nextOffset;
1296 
1297  LWLockRelease(MultiXactGenLock);
1298 
1299  if (MultiXactIdPrecedes(multi, oldestMXact))
1300  ereport(ERROR,
1301  (errcode(ERRCODE_INTERNAL_ERROR),
1302  errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
1303  multi)));
1304 
1305  if (!MultiXactIdPrecedes(multi, nextMXact))
1306  ereport(ERROR,
1307  (errcode(ERRCODE_INTERNAL_ERROR),
1308  errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
1309  multi)));
1310 
1311  /*
1312  * Find out the offset at which we need to start reading MultiXactMembers
1313  * and the number of members in the multixact. We determine the latter as
1314  * the difference between this multixact's starting offset and the next
1315  * one's. However, there are some corner cases to worry about:
1316  *
1317  * 1. This multixact may be the latest one created, in which case there is
1318  * no next one to look at. In this case the nextOffset value we just
1319  * saved is the correct endpoint.
1320  *
1321  * 2. The next multixact may still be in process of being filled in: that
1322  * is, another process may have done GetNewMultiXactId but not yet written
1323  * the offset entry for that ID. In that scenario, it is guaranteed that
1324  * the offset entry for that multixact exists (because GetNewMultiXactId
1325  * won't release MultiXactGenLock until it does) but contains zero
1326  * (because we are careful to pre-zero offset pages). Because
1327  * GetNewMultiXactId will never return zero as the starting offset for a
1328  * multixact, when we read zero as the next multixact's offset, we know we
1329  * have this case. We sleep for a bit and try again.
1330  *
1331  * 3. Because GetNewMultiXactId increments offset zero to offset one to
1332  * handle case #2, there is an ambiguity near the point of offset
1333  * wraparound. If we see next multixact's offset is one, is that our
1334  * multixact's actual endpoint, or did it end at zero with a subsequent
1335  * increment? We handle this using the knowledge that if the zero'th
1336  * member slot wasn't filled, it'll contain zero, and zero isn't a valid
1337  * transaction ID so it can't be a multixact member. Therefore, if we
1338  * read a zero from the members array, just ignore it.
1339  *
1340  * This is all pretty messy, but the mess occurs only in infrequent corner
1341  * cases, so it seems better than holding the MultiXactGenLock for a long
1342  * time on every multixact creation.
1343  */
1344 retry:
1345  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1346 
1347  pageno = MultiXactIdToOffsetPage(multi);
1348  entryno = MultiXactIdToOffsetEntry(multi);
1349 
1350  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
1351  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1352  offptr += entryno;
1353  offset = *offptr;
1354 
1355  Assert(offset != 0);
1356 
1357  /*
1358  * Use the same increment rule as GetNewMultiXactId(), that is, don't
1359  * handle wraparound explicitly until needed.
1360  */
1361  tmpMXact = multi + 1;
1362 
1363  if (nextMXact == tmpMXact)
1364  {
1365  /* Corner case 1: there is no next multixact */
1366  length = nextOffset - offset;
1367  }
1368  else
1369  {
1370  MultiXactOffset nextMXOffset;
1371 
1372  /* handle wraparound if needed */
1373  if (tmpMXact < FirstMultiXactId)
1374  tmpMXact = FirstMultiXactId;
1375 
1376  prev_pageno = pageno;
1377 
1378  pageno = MultiXactIdToOffsetPage(tmpMXact);
1379  entryno = MultiXactIdToOffsetEntry(tmpMXact);
1380 
1381  if (pageno != prev_pageno)
1382  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
1383 
1384  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1385  offptr += entryno;
1386  nextMXOffset = *offptr;
1387 
1388  if (nextMXOffset == 0)
1389  {
1390  /* Corner case 2: next multixact is still being filled in */
1391  LWLockRelease(MultiXactOffsetSLRULock);
1393  pg_usleep(1000L);
1394  goto retry;
1395  }
1396 
1397  length = nextMXOffset - offset;
1398  }
1399 
1400  LWLockRelease(MultiXactOffsetSLRULock);
1401 
1402  ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
1403 
1404  /* Now get the members themselves. */
1405  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
1406 
1407  truelength = 0;
1408  prev_pageno = -1;
1409  for (i = 0; i < length; i++, offset++)
1410  {
1411  TransactionId *xactptr;
1412  uint32 *flagsptr;
1413  int flagsoff;
1414  int bshift;
1415  int memberoff;
1416 
1417  pageno = MXOffsetToMemberPage(offset);
1418  memberoff = MXOffsetToMemberOffset(offset);
1419 
1420  if (pageno != prev_pageno)
1421  {
1422  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
1423  prev_pageno = pageno;
1424  }
1425 
1426  xactptr = (TransactionId *)
1427  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1428 
1429  if (!TransactionIdIsValid(*xactptr))
1430  {
1431  /* Corner case 3: we must be looking at unused slot zero */
1432  Assert(offset == 0);
1433  continue;
1434  }
1435 
1436  flagsoff = MXOffsetToFlagsOffset(offset);
1437  bshift = MXOffsetToFlagsBitShift(offset);
1438  flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1439 
1440  ptr[truelength].xid = *xactptr;
1441  ptr[truelength].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
1442  truelength++;
1443  }
1444 
1445  LWLockRelease(MultiXactMemberSLRULock);
1446 
1447  /* A multixid with zero members should not happen */
1448  Assert(truelength > 0);
1449 
1450  /*
1451  * Copy the result into the local cache.
1452  */
1453  mXactCachePut(multi, truelength, ptr);
1454 
1455  debug_elog3(DEBUG2, "GetMembers: no cache for %s",
1456  mxid_to_string(multi, truelength, ptr));
1457  *members = ptr;
1458  return truelength;
1459 }
unsigned int uint32
Definition: c.h:495
uint32 MultiXactOffset
Definition: c.h:653
uint32 TransactionId
Definition: c.h:641
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define DEBUG2
Definition: elog.h:29
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
@ LW_SHARED
Definition: lwlock.h:117
void * palloc(Size size)
Definition: mcxt.c:1201
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
Definition: multixact.c:1542
#define MXACT_MEMBER_XACT_BITMASK
Definition: multixact.c:132
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3163
static void MultiXactIdSetOldestVisible(void)
Definition: multixact.c:683
#define MXOffsetToFlagsBitShift(xid)
Definition: multixact.c:167
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1589
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163
#define MXOffsetToMemberOffset(xid)
Definition: multixact.c:172
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1657
#define debug_elog3(a, b, c)
Definition: multixact.c:335
static MultiXactStateData * MultiXactState
Definition: multixact.c:293
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
#define debug_elog2(a, b)
Definition: multixact.c:334
#define FirstMultiXactId
Definition: multixact.h:25
void pg_usleep(long microsec)
Definition: signal.c:53
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:430
TransactionId xid
Definition: multixact.h:62
MultiXactStatus status
Definition: multixact.h:63
MultiXactOffset nextOffset
Definition: multixact.c:206
MultiXactId nextMXact
Definition: multixact.c:203
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define TransactionIdIsValid(xid)
Definition: transam.h:41

References Assert(), CHECK_FOR_INTERRUPTS, DEBUG2, debug_elog2, debug_elog3, ereport, errcode(), errmsg(), ERROR, FirstMultiXactId, i, if(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactIdSetOldestVisible(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, MXACT_MEMBER_XACT_BITMASK, mXactCacheGetById(), mXactCachePut(), mxid_to_string(), MXOffsetToFlagsBitShift, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, MyBackendId, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactId, OldestVisibleMXactId, palloc(), pg_usleep(), SimpleLruReadPage(), MultiXactMember::status, TransactionIdIsValid, and MultiXactMember::xid.

Referenced by Do_MultiXactIdWait(), DoesMultiXactIdConflict(), FreezeMultiXactId(), GetMultiXactIdHintBits(), heap_lock_tuple(), heap_lock_updated_tuple_rec(), heap_tuple_should_freeze(), MultiXactIdExpand(), MultiXactIdGetUpdateXid(), MultiXactIdIsRunning(), pg_get_multixact_members(), and pgrowlocks().

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2514 of file multixact.c.

2515 {
2516  MultiXactId oldestMXact;
2517  MultiXactId nextMXact;
2518  int i;
2519 
2520  /*
2521  * This is the oldest valid value among all the OldestMemberMXactId[] and
2522  * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2523  */
2524  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2525 
2526  /*
2527  * We have to beware of the possibility that nextMXact is in the
2528  * wrapped-around state. We don't fix the counter itself here, but we
2529  * must be sure to use a valid value in our calculation.
2530  */
2531  nextMXact = MultiXactState->nextMXact;
2532  if (nextMXact < FirstMultiXactId)
2533  nextMXact = FirstMultiXactId;
2534 
2535  oldestMXact = nextMXact;
2536  for (i = 1; i <= MaxOldestSlot; i++)
2537  {
2538  MultiXactId thisoldest;
2539 
2540  thisoldest = OldestMemberMXactId[i];
2541  if (MultiXactIdIsValid(thisoldest) &&
2542  MultiXactIdPrecedes(thisoldest, oldestMXact))
2543  oldestMXact = thisoldest;
2544  thisoldest = OldestVisibleMXactId[i];
2545  if (MultiXactIdIsValid(thisoldest) &&
2546  MultiXactIdPrecedes(thisoldest, oldestMXact))
2547  oldestMXact = thisoldest;
2548  }
2549 
2550  LWLockRelease(MultiXactGenLock);
2551 
2552  return oldestMXact;
2553 }
#define MaxOldestSlot
Definition: multixact.c:290

References FirstMultiXactId, i, LW_SHARED, LWLockAcquire(), LWLockRelease(), MaxOldestSlot, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactState, MultiXactStateData::nextMXact, OldestMemberMXactId, and OldestVisibleMXactId.

Referenced by heapam_relation_set_new_filelocator(), vac_update_datfrozenxid(), and vacuum_get_cutoffs().

◆ multixact_desc()

void multixact_desc ( StringInfo  buf,
XLogReaderState record 
)

Definition at line 50 of file mxactdesc.c.

51 {
52  char *rec = XLogRecGetData(record);
53  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
54 
55  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE ||
57  {
58  int64 pageno;
59 
60  memcpy(&pageno, rec, sizeof(pageno));
61  appendStringInfo(buf, "%lld", (long long) pageno);
62  }
63  else if (info == XLOG_MULTIXACT_CREATE_ID)
64  {
66  int i;
67 
68  appendStringInfo(buf, "%u offset %u nmembers %d: ", xlrec->mid,
69  xlrec->moff, xlrec->nmembers);
70  for (i = 0; i < xlrec->nmembers; i++)
71  out_member(buf, &xlrec->members[i]);
72  }
73  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
74  {
76 
77  appendStringInfo(buf, "offsets [%u, %u), members [%u, %u)",
78  xlrec->startTruncOff, xlrec->endTruncOff,
79  xlrec->startTruncMemb, xlrec->endTruncMemb);
80  }
81 }
unsigned char uint8
Definition: c.h:493
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:73
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:72
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:75
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:74
static void out_member(StringInfo buf, MultiXactMember *member)
Definition: mxactdesc.c:20
static char * buf
Definition: pg_test_fsync.c:73
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
MultiXactId mid
Definition: multixact.h:79
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:82
MultiXactOffset moff
Definition: multixact.h:80
MultiXactId endTruncOff
Definition: multixact.h:93
MultiXactOffset startTruncMemb
Definition: multixact.h:96
MultiXactOffset endTruncMemb
Definition: multixact.h:97
MultiXactId startTruncOff
Definition: multixact.h:92
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define XLR_INFO_MASK
Definition: xlogrecord.h:62

References appendStringInfo(), buf, xl_multixact_truncate::endTruncMemb, xl_multixact_truncate::endTruncOff, i, xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, xl_multixact_create::nmembers, out_member(), xl_multixact_truncate::startTruncMemb, xl_multixact_truncate::startTruncOff, XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_TRUNCATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, XLogRecGetData, XLogRecGetInfo, and XLR_INFO_MASK.

◆ multixact_identify()

const char* multixact_identify ( uint8  info)

Definition at line 84 of file mxactdesc.c.

85 {
86  const char *id = NULL;
87 
88  switch (info & ~XLR_INFO_MASK)
89  {
91  id = "ZERO_OFF_PAGE";
92  break;
94  id = "ZERO_MEM_PAGE";
95  break;
97  id = "CREATE_ID";
98  break;
100  id = "TRUNCATE_ID";
101  break;
102  }
103 
104  return id;
105 }

References XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_TRUNCATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, and XLR_INFO_MASK.

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 3240 of file multixact.c.

3241 {
3242  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3243 
3244  /* Backup blocks are not used in multixact records */
3245  Assert(!XLogRecHasAnyBlockRefs(record));
3246 
3247  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3248  {
3249  int64 pageno;
3250  int slotno;
3251 
3252  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3253 
3254  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
3255 
3256  slotno = ZeroMultiXactOffsetPage(pageno, false);
3258  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3259 
3260  LWLockRelease(MultiXactOffsetSLRULock);
3261  }
3262  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3263  {
3264  int64 pageno;
3265  int slotno;
3266 
3267  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3268 
3269  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
3270 
3271  slotno = ZeroMultiXactMemberPage(pageno, false);
3273  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3274 
3275  LWLockRelease(MultiXactMemberSLRULock);
3276  }
3277  else if (info == XLOG_MULTIXACT_CREATE_ID)
3278  {
3279  xl_multixact_create *xlrec =
3280  (xl_multixact_create *) XLogRecGetData(record);
3281  TransactionId max_xid;
3282  int i;
3283 
3284  /* Store the data back into the SLRU files */
3285  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3286  xlrec->members);
3287 
3288  /* Make sure nextMXact/nextOffset are beyond what this record has */
3289  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3290  xlrec->moff + xlrec->nmembers);
3291 
3292  /*
3293  * Make sure nextXid is beyond any XID mentioned in the record. This
3294  * should be unnecessary, since any XID found here ought to have other
3295  * evidence in the XLOG, but let's be safe.
3296  */
3297  max_xid = XLogRecGetXid(record);
3298  for (i = 0; i < xlrec->nmembers; i++)
3299  {
3300  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3301  max_xid = xlrec->members[i].xid;
3302  }
3303 
3305  }
3306  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3307  {
3308  xl_multixact_truncate xlrec;
3309  int64 pageno;
3310 
3311  memcpy(&xlrec, XLogRecGetData(record),
3313 
3314  elog(DEBUG1, "replaying multixact truncation: "
3315  "offsets [%u, %u), offsets segments [%x, %x), "
3316  "members [%u, %u), members segments [%x, %x)",
3317  xlrec.startTruncOff, xlrec.endTruncOff,
3320  xlrec.startTruncMemb, xlrec.endTruncMemb,
3323 
3324  /* should not be required, but more than cheap enough */
3325  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3326 
3327  /*
3328  * Advance the horizon values, so they're current at the end of
3329  * recovery.
3330  */
3331  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3332 
3334 
3335  /*
3336  * During XLOG replay, latest_page_number isn't necessarily set up
3337  * yet; insert a suitable value to bypass the sanity test in
3338  * SimpleLruTruncate.
3339  */
3340  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3341  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3342  pageno);
3344 
3345  LWLockRelease(MultiXactTruncationLock);
3346  }
3347  else
3348  elog(PANIC, "multixact_redo: unknown op code %u", info);
3349 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:433
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2923
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2895
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2220
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:864
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2369
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
#define SizeOfMultiXactTruncate
Definition: multixact.h:100
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:304
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:412
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:417

References AdvanceNextFullTransactionIdPastXid(), Assert(), DEBUG1, elog(), xl_multixact_truncate::endTruncMemb, xl_multixact_truncate::endTruncOff, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, MultiXactAdvanceNextMXact(), MultiXactIdToOffsetPage, MultiXactIdToOffsetSegment, MultiXactMemberCtl, MultiXactOffsetCtl, MXOffsetToMemberSegment, xl_multixact_create::nmembers, xl_multixact_truncate::oldestMultiDB, PANIC, PerformMembersTruncation(), PerformOffsetsTruncation(), pg_atomic_write_u64(), RecordNewMultiXact(), SetMultiXactIdLimit(), SimpleLruWritePage(), SizeOfMultiXactTruncate, xl_multixact_truncate::startTruncMemb, xl_multixact_truncate::startTruncOff, TransactionIdPrecedes(), MultiXactMember::xid, XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_TRUNCATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, XLogRecGetData, XLogRecGetInfo, XLogRecGetXid, XLogRecHasAnyBlockRefs, XLR_INFO_MASK, ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

◆ multixact_twophase_postabort()

void multixact_twophase_postabort ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1815 of file multixact.c.

1817 {
1818  multixact_twophase_postcommit(xid, info, recdata, len);
1819 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1800
const void size_t len

References len, and multixact_twophase_postcommit().

◆ multixact_twophase_postcommit()

void multixact_twophase_postcommit ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1800 of file multixact.c.

1802 {
1803  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, true);
1804 
1805  Assert(len == sizeof(MultiXactId));
1806 
1807  OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
1808 }
int BackendId
Definition: backendid.h:21
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:919

References Assert(), InvalidMultiXactId, len, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

Referenced by multixact_twophase_postabort().

◆ multixact_twophase_recover()

void multixact_twophase_recover ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1779 of file multixact.c.

1781 {
1782  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1783  MultiXactId oldestMember;
1784 
1785  /*
1786  * Get the oldest member XID from the state file record, and set it in the
1787  * OldestMemberMXactId slot reserved for this prepared transaction.
1788  */
1789  Assert(len == sizeof(MultiXactId));
1790  oldestMember = *((MultiXactId *) recdata);
1791 
1792  OldestMemberMXactId[dummyBackendId] = oldestMember;
1793 }

References Assert(), len, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2369 of file multixact.c.

2371 {
2372  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2374  {
2375  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2376  MultiXactState->nextMXact = minMulti;
2377  }
2378  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2379  {
2380  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2381  minMultiOffset);
2382  MultiXactState->nextOffset = minMultiOffset;
2383  }
2384  LWLockRelease(MultiXactGenLock);
2385 }
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3189

References DEBUG2, debug_elog3, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdPrecedes(), MultiXactOffsetPrecedes(), MultiXactState, MultiXactStateData::nextMXact, and MultiXactStateData::nextOffset.

Referenced by multixact_redo(), and xlog_redo().

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2394 of file multixact.c.

2395 {
2396  Assert(InRecovery);
2397 
2399  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2400 }
bool InRecovery
Definition: xlogutils.c:53

References Assert(), InRecovery, MultiXactIdPrecedes(), MultiXactState, MultiXactStateData::oldestMultiXactId, and SetMultiXactIdLimit().

Referenced by xlog_redo().

◆ MultiXactGetCheckptMulti()

void MultiXactGetCheckptMulti ( bool  is_shutdown,
MultiXactId nextMulti,
MultiXactOffset nextMultiOffset,
MultiXactId oldestMulti,
Oid oldestMultiDB 
)

Definition at line 2140 of file multixact.c.

2145 {
2146  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2147  *nextMulti = MultiXactState->nextMXact;
2148  *nextMultiOffset = MultiXactState->nextOffset;
2149  *oldestMulti = MultiXactState->oldestMultiXactId;
2150  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2151  LWLockRelease(MultiXactGenLock);
2152 
2154  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2155  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2156 }
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:338

References DEBUG2, debug_elog6, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactState, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, and MultiXactStateData::oldestMultiXactId.

Referenced by CreateCheckPoint().

◆ MultiXactIdCreate()

MultiXactId MultiXactIdCreate ( TransactionId  xid1,
MultiXactStatus  status1,
TransactionId  xid2,
MultiXactStatus  status2 
)

Definition at line 387 of file multixact.c.

389 {
390  MultiXactId newMulti;
391  MultiXactMember members[2];
392 
395 
396  Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));
397 
398  /* MultiXactIdSetOldestMember() must have been called already. */
400 
401  /*
402  * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
403  * are still running. In typical usage, xid2 will be our own XID and the
404  * caller just did a check on xid1, so it'd be wasted effort.
405  */
406 
407  members[0].xid = xid1;
408  members[0].status = status1;
409  members[1].xid = xid2;
410  members[1].status = status2;
411 
412  newMulti = MultiXactIdCreateFromMembers(2, members);
413 
414  debug_elog3(DEBUG2, "Create: %s",
415  mxid_to_string(newMulti, 2, members));
416 
417  return newMulti;
418 }
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:768
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43

References Assert(), DEBUG2, debug_elog3, MultiXactIdCreateFromMembers(), MultiXactIdIsValid, mxid_to_string(), MyBackendId, OldestMemberMXactId, MultiXactMember::status, TransactionIdEquals, TransactionIdIsValid, and MultiXactMember::xid.

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 768 of file multixact.c.

769 {
770  MultiXactId multi;
771  MultiXactOffset offset;
772  xl_multixact_create xlrec;
773 
774  debug_elog3(DEBUG2, "Create: %s",
775  mxid_to_string(InvalidMultiXactId, nmembers, members));
776 
777  /*
778  * See if the same set of members already exists in our cache; if so, just
779  * re-use that MultiXactId. (Note: it might seem that looking in our
780  * cache is insufficient, and we ought to search disk to see if a
781  * duplicate definition already exists. But since we only ever create
782  * MultiXacts containing our own XID, in most cases any such MultiXacts
783  * were in fact created by us, and so will be in our cache. There are
784  * corner cases where someone else added us to a MultiXact without our
785  * knowledge, but it's not worth checking for.)
786  */
787  multi = mXactCacheGetBySet(nmembers, members);
788  if (MultiXactIdIsValid(multi))
789  {
790  debug_elog2(DEBUG2, "Create: in cache!");
791  return multi;
792  }
793 
794  /* Verify that there is a single update Xid among the given members. */
795  {
796  int i;
797  bool has_update = false;
798 
799  for (i = 0; i < nmembers; i++)
800  {
801  if (ISUPDATE_from_mxstatus(members[i].status))
802  {
803  if (has_update)
804  elog(ERROR, "new multixact has more than one updating member: %s",
805  mxid_to_string(InvalidMultiXactId, nmembers, members));
806  has_update = true;
807  }
808  }
809  }
810 
811  /*
812  * Assign the MXID and offsets range to use, and make sure there is space
813  * in the OFFSETs and MEMBERs files. NB: this routine does
814  * START_CRIT_SECTION().
815  *
816  * Note: unlike MultiXactIdCreate and MultiXactIdExpand, we do not check
817  * that we've called MultiXactIdSetOldestMember here. This is because
818  * this routine is used in some places to create new MultiXactIds of which
819  * the current backend is not a member, notably during freezing of multis
820  * in vacuum. During vacuum, in particular, it would be unacceptable to
821  * keep OldestMulti set, in case it runs for long.
822  */
823  multi = GetNewMultiXactId(nmembers, &offset);
824 
825  /* Make an XLOG entry describing the new MXID. */
826  xlrec.mid = multi;
827  xlrec.moff = offset;
828  xlrec.nmembers = nmembers;
829 
830  /*
831  * XXX Note: there's a lot of padding space in MultiXactMember. We could
832  * find a more compact representation of this Xlog record -- perhaps all
833  * the status flags in one XLogRecData, then all the xids in another one?
834  * Not clear that it's worth the trouble though.
835  */
836  XLogBeginInsert();
837  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactCreate);
838  XLogRegisterData((char *) members, nmembers * sizeof(MultiXactMember));
839 
840  (void) XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_CREATE_ID);
841 
842  /* Now enter the information into the OFFSETs and MEMBERs logs */
843  RecordNewMultiXact(multi, offset, nmembers, members);
844 
845  /* Done with critical section */
847 
848  /* Store the new MultiXactId in the local cache, too */
849  mXactCachePut(multi, nmembers, members);
850 
851  debug_elog2(DEBUG2, "Create: all done");
852 
853  return multi;
854 }
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
Definition: multixact.c:958
static MultiXactId mXactCacheGetBySet(int nmembers, MultiXactMember *members)
Definition: multixact.c:1499
#define ISUPDATE_from_mxstatus(status)
Definition: multixact.h:56
#define SizeOfMultiXactCreate
Definition: multixact.h:85
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:365
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:475
void XLogBeginInsert(void)
Definition: xloginsert.c:150

References DEBUG2, debug_elog2, debug_elog3, elog(), END_CRIT_SECTION, ERROR, GetNewMultiXactId(), i, InvalidMultiXactId, ISUPDATE_from_mxstatus, xl_multixact_create::mid, xl_multixact_create::moff, MultiXactIdIsValid, mXactCacheGetBySet(), mXactCachePut(), mxid_to_string(), xl_multixact_create::nmembers, RecordNewMultiXact(), SizeOfMultiXactCreate, XLOG_MULTIXACT_CREATE_ID, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by FreezeMultiXactId(), MultiXactIdCreate(), and MultiXactIdExpand().

◆ MultiXactIdExpand()

MultiXactId MultiXactIdExpand ( MultiXactId  multi,
TransactionId  xid,
MultiXactStatus  status 
)

Definition at line 440 of file multixact.c.

441 {
442  MultiXactId newMulti;
443  MultiXactMember *members;
444  MultiXactMember *newMembers;
445  int nmembers;
446  int i;
447  int j;
448 
449  Assert(MultiXactIdIsValid(multi));
451 
452  /* MultiXactIdSetOldestMember() must have been called already. */
454 
455  debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s",
456  multi, xid, mxstatus_to_string(status));
457 
458  /*
459  * Note: we don't allow for old multis here. The reason is that the only
460  * caller of this function does a check that the multixact is no longer
461  * running.
462  */
463  nmembers = GetMultiXactIdMembers(multi, &members, false, false);
464 
465  if (nmembers < 0)
466  {
467  MultiXactMember member;
468 
469  /*
470  * The MultiXactId is obsolete. This can only happen if all the
471  * MultiXactId members stop running between the caller checking and
472  * passing it to us. It would be better to return that fact to the
473  * caller, but it would complicate the API and it's unlikely to happen
474  * too often, so just deal with it by creating a singleton MultiXact.
475  */
476  member.xid = xid;
477  member.status = status;
478  newMulti = MultiXactIdCreateFromMembers(1, &member);
479 
480  debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
481  multi, newMulti);
482  return newMulti;
483  }
484 
485  /*
486  * If the TransactionId is already a member of the MultiXactId with the
487  * same status, just return the existing MultiXactId.
488  */
489  for (i = 0; i < nmembers; i++)
490  {
491  if (TransactionIdEquals(members[i].xid, xid) &&
492  (members[i].status == status))
493  {
494  debug_elog4(DEBUG2, "Expand: %u is already a member of %u",
495  xid, multi);
496  pfree(members);
497  return multi;
498  }
499  }
500 
501  /*
502  * Determine which of the members of the MultiXactId are still of
503  * interest. This is any running transaction, and also any transaction
504  * that grabbed something stronger than just a lock and was committed. (An
505  * update that aborted is of no interest here; and having more than one
506  * update Xid in a multixact would cause errors elsewhere.)
507  *
508  * Removing dead members is not just an optimization: freezing of tuples
509  * whose Xmax are multis depends on this behavior.
510  *
511  * Note we have the same race condition here as above: j could be 0 at the
512  * end of the loop.
513  */
514  newMembers = (MultiXactMember *)
515  palloc(sizeof(MultiXactMember) * (nmembers + 1));
516 
517  for (i = 0, j = 0; i < nmembers; i++)
518  {
519  if (TransactionIdIsInProgress(members[i].xid) ||
520  (ISUPDATE_from_mxstatus(members[i].status) &&
521  TransactionIdDidCommit(members[i].xid)))
522  {
523  newMembers[j].xid = members[i].xid;
524  newMembers[j++].status = members[i].status;
525  }
526  }
527 
528  newMembers[j].xid = xid;
529  newMembers[j++].status = status;
530  newMulti = MultiXactIdCreateFromMembers(j, newMembers);
531 
532  pfree(members);
533  pfree(newMembers);
534 
535  debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);
536 
537  return newMulti;
538 }
int j
Definition: isn.c:74
void pfree(void *pointer)
Definition: mcxt.c:1431
#define debug_elog5(a, b, c, d, e)
Definition: multixact.c:337
#define debug_elog4(a, b, c, d)
Definition: multixact.c:336
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1634
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
Definition: multixact.c:1225
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1389
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126

References Assert(), DEBUG2, debug_elog3, debug_elog4, debug_elog5, GetMultiXactIdMembers(), i, ISUPDATE_from_mxstatus, j, MultiXactIdCreateFromMembers(), MultiXactIdIsValid, mxstatus_to_string(), MyBackendId, OldestMemberMXactId, palloc(), pfree(), MultiXactMember::status, TransactionIdDidCommit(), TransactionIdEquals, TransactionIdIsInProgress(), TransactionIdIsValid, and MultiXactMember::xid.

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdIsRunning()

bool MultiXactIdIsRunning ( MultiXactId  multi,
bool  isLockOnly 
)

Definition at line 552 of file multixact.c.

553 {
554  MultiXactMember *members;
555  int nmembers;
556  int i;
557 
558  debug_elog3(DEBUG2, "IsRunning %u?", multi);
559 
560  /*
561  * "false" here means we assume our callers have checked that the given
562  * multi cannot possibly come from a pg_upgraded database.
563  */
564  nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
565 
566  if (nmembers <= 0)
567  {
568  debug_elog2(DEBUG2, "IsRunning: no members");
569  return false;
570  }
571 
572  /*
573  * Checking for myself is cheap compared to looking in shared memory;
574  * return true if any live subtransaction of the current top-level
575  * transaction is a member.
576  *
577  * This is not needed for correctness, it's just a fast path.
578  */
579  for (i = 0; i < nmembers; i++)
580  {
581  if (TransactionIdIsCurrentTransactionId(members[i].xid))
582  {
583  debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i);
584  pfree(members);
585  return true;
586  }
587  }
588 
589  /*
590  * This could be made faster by having another entry point in procarray.c,
591  * walking the PGPROC array only once for all the members. But in most
592  * cases nmembers should be small enough that it doesn't much matter.
593  */
594  for (i = 0; i < nmembers; i++)
595  {
596  if (TransactionIdIsInProgress(members[i].xid))
597  {
598  debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running",
599  i, members[i].xid);
600  pfree(members);
601  return true;
602  }
603  }
604 
605  pfree(members);
606 
607  debug_elog3(DEBUG2, "IsRunning: %u is not running", multi);
608 
609  return false;
610 }
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:926

References DEBUG2, debug_elog2, debug_elog3, debug_elog4, GetMultiXactIdMembers(), i, pfree(), TransactionIdIsCurrentTransactionId(), and TransactionIdIsInProgress().

Referenced by compute_new_xmax_infomask(), FreezeMultiXactId(), HeapTupleSatisfiesUpdate(), and HeapTupleSatisfiesVacuumHorizon().

◆ MultiXactIdPrecedes()

◆ MultiXactIdPrecedesOrEquals()

bool MultiXactIdPrecedesOrEquals ( MultiXactId  multi1,
MultiXactId  multi2 
)

Definition at line 3177 of file multixact.c.

3178 {
3179  int32 diff = (int32) (multi1 - multi2);
3180 
3181  return (diff <= 0);
3182 }

Referenced by check_mxid_in_range(), heap_tuple_should_freeze(), heap_vacuum_rel(), TruncateMultiXact(), and vacuum_get_cutoffs().

◆ MultiXactIdSetOldestMember()

void MultiXactIdSetOldestMember ( void  )

Definition at line 626 of file multixact.c.

627 {
629  {
630  MultiXactId nextMXact;
631 
632  /*
633  * You might think we don't need to acquire a lock here, since
634  * fetching and storing of TransactionIds is probably atomic, but in
635  * fact we do: suppose we pick up nextMXact and then lose the CPU for
636  * a long time. Someone else could advance nextMXact, and then
637  * another someone else could compute an OldestVisibleMXactId that
638  * would be after the value we are going to store when we get control
639  * back. Which would be wrong.
640  *
641  * Note that a shared lock is sufficient, because it's enough to stop
642  * someone from advancing nextMXact; and nobody else could be trying
643  * to write to our OldestMember entry, only reading (and we assume
644  * storing it is atomic.)
645  */
646  LWLockAcquire(MultiXactGenLock, LW_SHARED);
647 
648  /*
649  * We have to beware of the possibility that nextMXact is in the
650  * wrapped-around state. We don't fix the counter itself here, but we
651  * must be sure to store a valid value in our array entry.
652  */
653  nextMXact = MultiXactState->nextMXact;
654  if (nextMXact < FirstMultiXactId)
655  nextMXact = FirstMultiXactId;
656 
657  OldestMemberMXactId[MyBackendId] = nextMXact;
658 
659  LWLockRelease(MultiXactGenLock);
660 
661  debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
662  MyBackendId, nextMXact);
663  }
664 }

References DEBUG2, debug_elog4, FirstMultiXactId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactState, MyBackendId, MultiXactStateData::nextMXact, and OldestMemberMXactId.

Referenced by heap_delete(), heap_lock_tuple(), heap_lock_updated_tuple(), and heap_update().

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2832 of file multixact.c.

2833 {
2834  MultiXactOffset members;
2835  uint32 multixacts;
2836  uint32 victim_multixacts;
2837  double fraction;
2838 
2839  /* If we can't determine member space utilization, assume the worst. */
2840  if (!ReadMultiXactCounts(&multixacts, &members))
2841  return 0;
2842 
2843  /* If member space utilization is low, no special action is required. */
2844  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2846 
2847  /*
2848  * Compute a target for relminmxid advancement. The number of multixacts
2849  * we try to eliminate from the system is based on how far we are past
2850  * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2851  */
2852  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2854  victim_multixacts = multixacts * fraction;
2855 
2856  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2857  if (victim_multixacts > multixacts)
2858  return 0;
2859  return multixacts - victim_multixacts;
2860 }
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:128
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:177
static bool ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
Definition: multixact.c:2780
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:178

References autovacuum_multixact_freeze_max_age, MULTIXACT_MEMBER_DANGER_THRESHOLD, MULTIXACT_MEMBER_SAFE_THRESHOLD, and ReadMultiXactCounts().

Referenced by do_autovacuum(), do_start_worker(), and vacuum_get_cutoffs().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3426 of file multixact.c.

3427 {
3428  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3429 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1664

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3417 of file multixact.c.

3418 {
3419  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3420 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2186 of file multixact.c.

2188 {
2189  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2190  nextMulti, nextMultiOffset);
2191  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2192  MultiXactState->nextMXact = nextMulti;
2193  MultiXactState->nextOffset = nextMultiOffset;
2194  LWLockRelease(MultiXactGenLock);
2195 
2196  /*
2197  * During a binary upgrade, make sure that the offsets SLRU is large
2198  * enough to contain the next value that would be created.
2199  *
2200  * We need to do this pretty early during the first startup in binary
2201  * upgrade mode: before StartupMultiXact() in fact, because this routine
2202  * is called even before that by StartupXLOG(). And we can't do it
2203  * earlier than at this point, because during that first call of this
2204  * routine we determine the MultiXactState->nextMXact value that
2205  * MaybeExtendOffsetSlru needs.
2206  */
2207  if (IsBinaryUpgrade)
2209 }
bool IsBinaryUpgrade
Definition: globals.c:117
static void MaybeExtendOffsetSlru(void)
Definition: multixact.c:1977

References DEBUG2, debug_elog4, IsBinaryUpgrade, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaybeExtendOffsetSlru(), MultiXactState, MultiXactStateData::nextMXact, and MultiXactStateData::nextOffset.

Referenced by BootStrapXLOG(), StartupXLOG(), and xlog_redo().

◆ MultiXactShmemInit()

void MultiXactShmemInit ( void  )

Definition at line 1844 of file multixact.c.

1845 {
1846  bool found;
1847 
1848  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1849 
1852 
1854  "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
1855  MultiXactOffsetSLRULock, "pg_multixact/offsets",
1858  false);
1861  "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
1862  MultiXactMemberSLRULock, "pg_multixact/members",
1865  false);
1866  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1867 
1868  /* Initialize our shared state struct */
1869  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1871  &found);
1872  if (!IsUnderPostmaster)
1873  {
1874  Assert(!found);
1875 
1876  /* Make sure we zero out the per-backend state */
1878  }
1879  else
1880  Assert(found);
1881 
1882  /*
1883  * Set up array pointers. Note that perBackendXactIds[0] is wasted space
1884  * since we only use indexes 1..MaxOldestSlot in each array.
1885  */
1888 }
#define MemSet(start, val, len)
Definition: c.h:1009
bool IsUnderPostmaster
Definition: globals.c:116
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:185
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:184
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3143
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3123
#define NUM_MULTIXACTOFFSET_BUFFERS
Definition: multixact.h:33
#define NUM_MULTIXACTMEMBER_BUFFERS
Definition: multixact.h:34
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:388
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition: slru.c:215
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:168
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:283
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40

References Assert(), DEBUG2, debug_elog2, IsUnderPostmaster, LWTRANCHE_MULTIXACTMEMBER_BUFFER, LWTRANCHE_MULTIXACTOFFSET_BUFFER, MaxOldestSlot, MemSet, MULTIXACT_OFFSETS_PER_PAGE, MultiXactMemberCtl, MultiXactMemberPagePrecedes(), MultiXactOffsetCtl, MultiXactOffsetPagePrecedes(), MultiXactState, NUM_MULTIXACTMEMBER_BUFFERS, NUM_MULTIXACTOFFSET_BUFFERS, OldestMemberMXactId, OldestVisibleMXactId, MultiXactStateData::perBackendXactIds, SHARED_MULTIXACT_STATE_SIZE, ShmemInitStruct(), SimpleLruInit(), SlruPagePrecedesUnitTests, SYNC_HANDLER_MULTIXACT_MEMBER, and SYNC_HANDLER_MULTIXACT_OFFSET.

Referenced by CreateOrAttachShmemStructs().

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1827 of file multixact.c.

1828 {
1829  Size size;
1830 
1831  /* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
1832 #define SHARED_MULTIXACT_STATE_SIZE \
1833  add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
1834  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1835 
1839 
1840  return size;
1841 }
size_t Size
Definition: c.h:594
Size add_size(Size s1, Size s2)
Definition: shmem.c:494
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:183

References add_size(), NUM_MULTIXACTMEMBER_BUFFERS, NUM_MULTIXACTOFFSET_BUFFERS, SHARED_MULTIXACT_STATE_SIZE, and SimpleLruShmemSize().

Referenced by CalculateShmemSize().

◆ mxid_to_string()

char* mxid_to_string ( MultiXactId  multi,
int  nmembers,
MultiXactMember members 
)

Definition at line 1657 of file multixact.c.

1658 {
1659  static char *str = NULL;
1661  int i;
1662 
1663  if (str != NULL)
1664  pfree(str);
1665 
1666  initStringInfo(&buf);
1667 
1668  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1669  mxstatus_to_string(members[0].status));
1670 
1671  for (i = 1; i < nmembers; i++)
1672  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1673  mxstatus_to_string(members[i].status));
1674 
1675  appendStringInfoChar(&buf, ']');
1677  pfree(buf.data);
1678  return str;
1679 }
MemoryContext TopMemoryContext
Definition: mcxt.c:141
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1606
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

References appendStringInfo(), appendStringInfoChar(), buf, i, initStringInfo(), MemoryContextStrdup(), mxstatus_to_string(), pfree(), generate_unaccent_rules::str, and TopMemoryContext.

Referenced by GetMultiXactIdMembers(), MultiXactIdCreate(), MultiXactIdCreateFromMembers(), mXactCacheGetById(), mXactCacheGetBySet(), and mXactCachePut().

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1730 of file multixact.c.

1731 {
1732  MultiXactId myOldestMember;
1733 
1734  /*
1735  * Transfer our OldestMemberMXactId value to the slot reserved for the
1736  * prepared transaction.
1737  */
1738  myOldestMember = OldestMemberMXactId[MyBackendId];
1739  if (MultiXactIdIsValid(myOldestMember))
1740  {
1741  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1742 
1743  /*
1744  * Even though storing MultiXactId is atomic, acquire lock to make
1745  * sure others see both changes, not just the reset of the slot of the
1746  * current backend. Using a volatile pointer might suffice, but this
1747  * isn't a hot spot.
1748  */
1749  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1750 
1751  OldestMemberMXactId[dummyBackendId] = myOldestMember;
1753 
1754  LWLockRelease(MultiXactGenLock);
1755  }
1756 
1757  /*
1758  * We don't need to transfer OldestVisibleMXactId value, because the
1759  * transaction is not going to be looking at any more multixacts once it's
1760  * prepared.
1761  *
1762  * We assume that storing a MultiXactId is atomic and so we need not take
1763  * MultiXactGenLock to do this.
1764  */
1766 
1767  /*
1768  * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1769  */
1770  MXactContext = NULL;
1772 }

References dclist_init(), InvalidMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MXactCache, MXactContext, MyBackendId, OldestMemberMXactId, OldestVisibleMXactId, and TwoPhaseGetDummyBackendId().

Referenced by PrepareTransaction().

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 744 of file multixact.c.

745 {
746  LWLockAcquire(MultiXactGenLock, LW_SHARED);
749  LWLockRelease(MultiXactGenLock);
750 
751  if (*oldest < FirstMultiXactId)
752  *oldest = FirstMultiXactId;
753  if (*next < FirstMultiXactId)
755 }
static int32 next
Definition: blutils.c:221

References FirstMultiXactId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactState, next, MultiXactStateData::nextMXact, and MultiXactStateData::oldestMultiXactId.

Referenced by update_cached_mxid_range().

◆ ReadNextMultiXactId()

MultiXactId ReadNextMultiXactId ( void  )

Definition at line 724 of file multixact.c.

725 {
726  MultiXactId mxid;
727 
728  /* XXX we could presumably do this without a lock. */
729  LWLockAcquire(MultiXactGenLock, LW_SHARED);
730  mxid = MultiXactState->nextMXact;
731  LWLockRelease(MultiXactGenLock);
732 
733  if (mxid < FirstMultiXactId)
734  mxid = FirstMultiXactId;
735 
736  return mxid;
737 }

References FirstMultiXactId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactState, and MultiXactStateData::nextMXact.

Referenced by ATRewriteTables(), AutoVacWorkerMain(), do_start_worker(), mxid_age(), refresh_by_heap_swap(), vac_update_datfrozenxid(), vac_update_relstats(), vacuum_get_cutoffs(), and vacuum_xid_failsafe_check().

◆ SetMultiXactIdLimit()

void SetMultiXactIdLimit ( MultiXactId  oldest_datminmxid,
Oid  oldest_datoid,
bool  is_startup 
)

Definition at line 2220 of file multixact.c.

2222 {
2223  MultiXactId multiVacLimit;
2224  MultiXactId multiWarnLimit;
2225  MultiXactId multiStopLimit;
2226  MultiXactId multiWrapLimit;
2227  MultiXactId curMulti;
2228  bool needs_offset_vacuum;
2229 
2230  Assert(MultiXactIdIsValid(oldest_datminmxid));
2231 
2232  /*
2233  * We pretend that a wrap will happen halfway through the multixact ID
2234  * space, but that's not really true, because multixacts wrap differently
2235  * from transaction IDs. Note that, separately from any concern about
2236  * multixact IDs wrapping, we must ensure that multixact members do not
2237  * wrap. Limits for that are set in SetOffsetVacuumLimit, not here.
2238  */
2239  multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
2240  if (multiWrapLimit < FirstMultiXactId)
2241  multiWrapLimit += FirstMultiXactId;
2242 
2243  /*
2244  * We'll refuse to continue assigning MultiXactIds once we get within 3M
2245  * multi of data loss. See SetTransactionIdLimit.
2246  */
2247  multiStopLimit = multiWrapLimit - 3000000;
2248  if (multiStopLimit < FirstMultiXactId)
2249  multiStopLimit -= FirstMultiXactId;
2250 
2251  /*
2252  * We'll start complaining loudly when we get within 40M multis of data
2253  * loss. This is kind of arbitrary, but if you let your gas gauge get
2254  * down to 2% of full, would you be looking for the next gas station? We
2255  * need to be fairly liberal about this number because there are lots of
2256  * scenarios where most transactions are done by automatic clients that
2257  * won't pay attention to warnings. (No, we're not gonna make this
2258  * configurable. If you know enough to configure it, you know enough to
2259  * not get in this kind of trouble in the first place.)
2260  */
2261  multiWarnLimit = multiWrapLimit - 40000000;
2262  if (multiWarnLimit < FirstMultiXactId)
2263  multiWarnLimit -= FirstMultiXactId;
2264 
2265  /*
2266  * We'll start trying to force autovacuums when oldest_datminmxid gets to
2267  * be more than autovacuum_multixact_freeze_max_age mxids old.
2268  *
2269  * Note: autovacuum_multixact_freeze_max_age is a PGC_POSTMASTER parameter
2270  * so that we don't have to worry about dealing with on-the-fly changes in
2271  * its value. See SetTransactionIdLimit.
2272  */
2273  multiVacLimit = oldest_datminmxid + autovacuum_multixact_freeze_max_age;
2274  if (multiVacLimit < FirstMultiXactId)
2275  multiVacLimit += FirstMultiXactId;
2276 
2277  /* Grab lock for just long enough to set the new limit values */
2278  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2279  MultiXactState->oldestMultiXactId = oldest_datminmxid;
2280  MultiXactState->oldestMultiXactDB = oldest_datoid;
2281  MultiXactState->multiVacLimit = multiVacLimit;
2282  MultiXactState->multiWarnLimit = multiWarnLimit;
2283  MultiXactState->multiStopLimit = multiStopLimit;
2284  MultiXactState->multiWrapLimit = multiWrapLimit;
2285  curMulti = MultiXactState->nextMXact;
2286  LWLockRelease(MultiXactGenLock);
2287 
2288  /* Log the info */
2289  ereport(DEBUG1,
2290  (errmsg_internal("MultiXactId wrap limit is %u, limited by database with OID %u",
2291  multiWrapLimit, oldest_datoid)));
2292 
2293  /*
2294  * Computing the actual limits is only possible once the data directory is
2295  * in a consistent state. There's no need to compute the limits while
2296  * still replaying WAL - no decisions about new multis are made even
2297  * though multixact creations might be replayed. So we'll only do further
2298  * checks after TrimMultiXact() has been called.
2299  */
2301  return;
2302 
2303  Assert(!InRecovery);
2304 
2305  /* Set limits for offset vacuum. */
2306  needs_offset_vacuum = SetOffsetVacuumLimit(is_startup);
2307 
2308  /*
2309  * If past the autovacuum force point, immediately signal an autovac
2310  * request. The reason for this is that autovac only processes one
2311  * database per invocation. Once it's finished cleaning up the oldest
2312  * database, it'll call here, and we'll signal the postmaster to start
2313  * another iteration immediately if there are still any old databases.
2314  */
2315  if ((MultiXactIdPrecedes(multiVacLimit, curMulti) ||
2316  needs_offset_vacuum) && IsUnderPostmaster)
2318 
2319  /* Give an immediate warning if past the wrap warn point */
2320  if (MultiXactIdPrecedes(multiWarnLimit, curMulti))
2321  {
2322  char *oldest_datname;
2323 
2324  /*
2325  * We can be called when not inside a transaction, for example during
2326  * StartupXLOG(). In such a case we cannot do database access, so we
2327  * must just report the oldest DB's OID.
2328  *
2329  * Note: it's also possible that get_database_name fails and returns
2330  * NULL, for example because the database just got dropped. We'll
2331  * still warn, even though the warning might now be unnecessary.
2332  */
2333  if (IsTransactionState())
2334  oldest_datname = get_database_name(oldest_datoid);
2335  else
2336  oldest_datname = NULL;
2337 
2338  if (oldest_datname)
2339  ereport(WARNING,
2340  (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
2341  "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
2342  multiWrapLimit - curMulti,
2343  oldest_datname,
2344  multiWrapLimit - curMulti),
2345  errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2346  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2347  else
2348  ereport(WARNING,
2349  (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
2350  "database with OID %u must be vacuumed before %u more MultiXactIds are used",
2351  multiWrapLimit - curMulti,
2352  oldest_datoid,
2353  multiWrapLimit - curMulti),
2354  errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2355  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2356  }
2357 }
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3089
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1185
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1162
int errhint(const char *fmt,...)
Definition: elog.c:1322
#define WARNING
Definition: elog.h:36
static bool SetOffsetVacuumLimit(bool is_startup)
Definition: multixact.c:2567
#define MaxMultiXactId
Definition: multixact.h:26
void SendPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:181
@ PMSIGNAL_START_AUTOVAC_LAUNCHER
Definition: pmsignal.h:38
MultiXactId multiWrapLimit
Definition: multixact.c:231
MultiXactId multiStopLimit
Definition: multixact.c:230
MultiXactId multiWarnLimit
Definition: multixact.c:229
MultiXactId multiVacLimit
Definition: multixact.c:228
bool IsTransactionState(void)
Definition: xact.c:378

References Assert(), autovacuum_multixact_freeze_max_age, DEBUG1, ereport, errhint(), errmsg_internal(), errmsg_plural(), MultiXactStateData::finishedStartup, FirstMultiXactId, get_database_name(), InRecovery, IsTransactionState(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxMultiXactId, MultiXactStateData::multiStopLimit, MultiXactStateData::multiVacLimit, MultiXactStateData::multiWarnLimit, MultiXactStateData::multiWrapLimit, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactState, MultiXactStateData::nextMXact, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, PMSIGNAL_START_AUTOVAC_LAUNCHER, SendPostmasterSignal(), SetOffsetVacuumLimit(), and WARNING.

Referenced by BootStrapXLOG(), multixact_redo(), MultiXactAdvanceOldest(), StartupXLOG(), TrimMultiXact(), and vac_truncate_clog().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2010 of file multixact.c.

2011 {
2014  int64 pageno;
2015 
2016  /*
2017  * Initialize offset's idea of the latest page number.
2018  */
2019  pageno = MultiXactIdToOffsetPage(multi);
2020  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2021  pageno);
2022 
2023  /*
2024  * Initialize member's idea of the latest page number.
2025  */
2026  pageno = MXOffsetToMemberPage(offset);
2027  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2028  pageno);
2029 }

References MultiXactIdToOffsetPage, MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, MXOffsetToMemberPage, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, and pg_atomic_write_u64().

Referenced by StartupXLOG().

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 2035 of file multixact.c.

2036 {
2037  MultiXactId nextMXact;
2038  MultiXactOffset offset;
2039  MultiXactId oldestMXact;
2040  Oid oldestMXactDB;
2041  int64 pageno;
2042  int entryno;
2043  int flagsoff;
2044 
2045  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2046  nextMXact = MultiXactState->nextMXact;
2047  offset = MultiXactState->nextOffset;
2048  oldestMXact = MultiXactState->oldestMultiXactId;
2049  oldestMXactDB = MultiXactState->oldestMultiXactDB;
2050  LWLockRelease(MultiXactGenLock);
2051 
2052  /*
2053  * (Re-)Initialize our idea of the latest page number for offsets.
2054  */
2055  pageno = MultiXactIdToOffsetPage(nextMXact);
2056  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2057  pageno);
2058 
2059  /* Clean up offsets state */
2060  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
2061 
2062  /*
2063  * Zero out the remainder of the current offsets page. See notes in
2064  * TrimCLOG() for background. Unlike CLOG, some WAL record covers every
2065  * pg_multixact SLRU mutation. Since, also unlike CLOG, we ignore the WAL
2066  * rule "write xlog before data," nextMXact successors may carry obsolete,
2067  * nonzero offset values. Zero those so case 2 of GetMultiXactIdMembers()
2068  * operates normally.
2069  */
2070  entryno = MultiXactIdToOffsetEntry(nextMXact);
2071  if (entryno != 0)
2072  {
2073  int slotno;
2074  MultiXactOffset *offptr;
2075 
2076  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2077  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2078  offptr += entryno;
2079 
2080  MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
2081 
2082  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2083  }
2084 
2085  LWLockRelease(MultiXactOffsetSLRULock);
2086 
2087  /*
2088  * And the same for members.
2089  *
2090  * (Re-)Initialize our idea of the latest page number for members.
2091  */
2092  pageno = MXOffsetToMemberPage(offset);
2093  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2094  pageno);
2095 
2096  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
2097 
2098  /*
2099  * Zero out the remainder of the current members page. See notes in
2100  * TrimCLOG() for motivation.
2101  */
2102  flagsoff = MXOffsetToFlagsOffset(offset);
2103  if (flagsoff != 0)
2104  {
2105  int slotno;
2106  TransactionId *xidptr;
2107  int memberoff;
2108 
2109  memberoff = MXOffsetToMemberOffset(offset);
2110  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2111  xidptr = (TransactionId *)
2112  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2113 
2114  MemSet(xidptr, 0, BLCKSZ - memberoff);
2115 
2116  /*
2117  * Note: we don't need to zero out the flag bits in the remaining
2118  * members of the current group, because they are always reset before
2119  * writing.
2120  */
2121 
2122  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2123  }
2124 
2125  LWLockRelease(MultiXactMemberSLRULock);
2126 
2127  /* signal that we're officially up */
2128  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2130  LWLockRelease(MultiXactGenLock);
2131 
2132  /* Now compute how far away the next members wraparound is. */
2133  SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2134 }
unsigned int Oid
Definition: postgres_ext.h:31

References MultiXactStateData::finishedStartup, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MemSet, MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, pg_atomic_write_u64(), SetMultiXactIdLimit(), and SimpleLruReadPage().

Referenced by StartupXLOG().

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  newOldestMulti,
Oid  newOldestMultiDB 
)

Definition at line 2948 of file multixact.c.

2949 {
2950  MultiXactId oldestMulti;
2951  MultiXactId nextMulti;
2952  MultiXactOffset newOldestOffset;
2953  MultiXactOffset oldestOffset;
2954  MultiXactOffset nextOffset;
2955  mxtruncinfo trunc;
2956  MultiXactId earliest;
2957 
2960 
2961  /*
2962  * We can only allow one truncation to happen at once. Otherwise parts of
2963  * members might vanish while we're doing lookups or similar. There's no
2964  * need to have an interlock with creating new multis or such, since those
2965  * are constrained by the limits (which only grow, never shrink).
2966  */
2967  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
2968 
2969  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2970  nextMulti = MultiXactState->nextMXact;
2971  nextOffset = MultiXactState->nextOffset;
2972  oldestMulti = MultiXactState->oldestMultiXactId;
2973  LWLockRelease(MultiXactGenLock);
2974  Assert(MultiXactIdIsValid(oldestMulti));
2975 
2976  /*
2977  * Make sure to only attempt truncation if there's values to truncate
2978  * away. In normal processing values shouldn't go backwards, but there's
2979  * some corner cases (due to bugs) where that's possible.
2980  */
2981  if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
2982  {
2983  LWLockRelease(MultiXactTruncationLock);
2984  return;
2985  }
2986 
2987  /*
2988  * Note we can't just plow ahead with the truncation; it's possible that
2989  * there are no segments to truncate, which is a problem because we are
2990  * going to attempt to read the offsets page to determine where to
2991  * truncate the members SLRU. So we first scan the directory to determine
2992  * the earliest offsets page number that we can read without error.
2993  *
2994  * When nextMXact is less than one segment away from multiWrapLimit,
2995  * SlruScanDirCbFindEarliest can find some early segment other than the
2996  * actual earliest. (MultiXactOffsetPagePrecedes(EARLIEST, LATEST)
2997  * returns false, because not all pairs of entries have the same answer.)
2998  * That can also arise when an earlier truncation attempt failed unlink()
2999  * or returned early from this function. The only consequence is
3000  * returning early, which wastes space that we could have liberated.
3001  *
3002  * NB: It's also possible that the page that oldestMulti is on has already
3003  * been truncated away, and we crashed before updating oldestMulti.
3004  */
3005  trunc.earliestExistingPage = -1;
3008  if (earliest < FirstMultiXactId)
3009  earliest = FirstMultiXactId;
3010 
3011  /* If there's nothing to remove, we can bail out early. */
3012  if (MultiXactIdPrecedes(oldestMulti, earliest))
3013  {
3014  LWLockRelease(MultiXactTruncationLock);
3015  return;
3016  }
3017 
3018  /*
3019  * First, compute the safe truncation point for MultiXactMember. This is
3020  * the starting offset of the oldest multixact.
3021  *
3022  * Hopefully, find_multixact_start will always work here, because we've
3023  * already checked that it doesn't precede the earliest MultiXact on disk.
3024  * But if it fails, don't truncate anything, and log a message.
3025  */
3026  if (oldestMulti == nextMulti)
3027  {
3028  /* there are NO MultiXacts */
3029  oldestOffset = nextOffset;
3030  }
3031  else if (!find_multixact_start(oldestMulti, &oldestOffset))
3032  {
3033  ereport(LOG,
3034  (errmsg("oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
3035  oldestMulti, earliest)));
3036  LWLockRelease(MultiXactTruncationLock);
3037  return;
3038  }
3039 
3040  /*
3041  * Secondly compute up to where to truncate. Lookup the corresponding
3042  * member offset for newOldestMulti for that.
3043  */
3044  if (newOldestMulti == nextMulti)
3045  {
3046  /* there are NO MultiXacts */
3047  newOldestOffset = nextOffset;
3048  }
3049  else if (!find_multixact_start(newOldestMulti, &newOldestOffset))
3050  {
3051  ereport(LOG,
3052  (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
3053  newOldestMulti)));
3054  LWLockRelease(MultiXactTruncationLock);
3055  return;
3056  }
3057 
3058  elog(DEBUG1, "performing multixact truncation: "
3059  "offsets [%u, %u), offsets segments [%x, %x), "
3060  "members [%u, %u), members segments [%x, %x)",
3061  oldestMulti, newOldestMulti,
3062  MultiXactIdToOffsetSegment(oldestMulti),
3063  MultiXactIdToOffsetSegment(newOldestMulti),
3064  oldestOffset, newOldestOffset,
3065  MXOffsetToMemberSegment(oldestOffset),
3066  MXOffsetToMemberSegment(newOldestOffset));
3067 
3068  /*
3069  * Do truncation, and the WAL logging of the truncation, in a critical
3070  * section. That way offsets/members cannot get out of sync anymore, i.e.
3071  * once consistent the newOldestMulti will always exist in members, even
3072  * if we crashed in the wrong moment.
3073  */
3075 
3076  /*
3077  * Prevent checkpoints from being scheduled concurrently. This is critical
3078  * because otherwise a truncation record might not be replayed after a
3079  * crash/basebackup, even though the state of the data directory would
3080  * require it.
3081  */
3084 
3085  /* WAL log truncation */
3086  WriteMTruncateXlogRec(newOldestMultiDB,
3087  oldestMulti, newOldestMulti,
3088  oldestOffset, newOldestOffset);
3089 
3090  /*
3091  * Update in-memory limits before performing the truncation, while inside
3092  * the critical section: Have to do it before truncation, to prevent
3093  * concurrent lookups of those values. Has to be inside the critical
3094  * section as otherwise a future call to this function would error out,
3095  * while looking up the oldest member in offsets, if our caller crashes
3096  * before updating the limits.
3097  */
3098  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
3099  MultiXactState->oldestMultiXactId = newOldestMulti;
3100  MultiXactState->oldestMultiXactDB = newOldestMultiDB;
3101  LWLockRelease(MultiXactGenLock);
3102 
3103  /* First truncate members */
3104  PerformMembersTruncation(oldestOffset, newOldestOffset);
3105 
3106  /* Then offsets */
3107  PerformOffsetsTruncation(oldestMulti, newOldestMulti);
3108 
3110 
3111  END_CRIT_SECTION();
3112  LWLockRelease(MultiXactTruncationLock);
3113 }
#define LOG
Definition: elog.h:31
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
static void WriteMTruncateXlogRec(Oid oldestMultiDB, MultiXactId startTruncOff, MultiXactId endTruncOff, MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
Definition: multixact.c:3215
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition: multixact.c:2742
static bool SlruScanDirCbFindEarliest(SlruCtl ctl, char *filename, int64 segpage, void *data)
Definition: multixact.c:2872
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3177
#define DELAY_CHKPT_START
Definition: proc.h:119
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1624
PGPROC * MyProc
Definition: proc.c:67
int delayChkptFlags
Definition: proc.h:231
int64 earliestExistingPage
Definition: multixact.c:2864
bool RecoveryInProgress(void)
Definition: xlog.c:6211

References Assert(), DEBUG1, DELAY_CHKPT_START, PGPROC::delayChkptFlags, mxtruncinfo::earliestExistingPage, elog(), END_CRIT_SECTION, ereport, errmsg(), find_multixact_start(), MultiXactStateData::finishedStartup, FirstMultiXactId, LOG, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MULTIXACT_OFFSETS_PER_PAGE, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactIdPrecedesOrEquals(), MultiXactIdToOffsetSegment, MultiXactOffsetCtl, MultiXactState, MXOffsetToMemberSegment, MyProc, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, PerformMembersTruncation(), PerformOffsetsTruncation(), RecoveryInProgress(), SlruScanDirCbFindEarliest(), SlruScanDirectory(), START_CRIT_SECTION, and WriteMTruncateXlogRec().

Referenced by vac_truncate_clog().