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 **xids, bool allow_old, 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 oldestMulti, Oid oldestMultiDB)
 
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 */
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 1686 of file multixact.c.

1687 {
1688  /*
1689  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1690  * which should only be valid while within a transaction.
1691  *
1692  * We assume that storing a MultiXactId is atomic and so we need not take
1693  * MultiXactGenLock to do this.
1694  */
1697 
1698  /*
1699  * Discard the local MultiXactId cache. Since MXactContext was created as
1700  * a child of TopTransactionContext, we needn't delete it explicitly.
1701  */
1702  MXactContext = NULL;
1704  MXactCacheMembers = 0;
1705 }
BackendId MyBackendId
Definition: globals.c:84
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
static dlist_head MXactCache
Definition: multixact.c:322
static int MXactCacheMembers
Definition: multixact.c:323
static MemoryContext MXactContext
Definition: multixact.c:324
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
#define InvalidMultiXactId
Definition: multixact.h:24

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

Referenced by AbortTransaction(), and CommitTransaction().

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1715 of file multixact.c.

1716 {
1717  MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1718 
1719  if (MultiXactIdIsValid(myOldestMember))
1721  &myOldestMember, sizeof(MultiXactId));
1722 }
TransactionId MultiXactId
Definition: c.h:597
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1238
#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 1894 of file multixact.c.

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

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

Referenced by BootStrapXLOG().

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2155 of file multixact.c.

2156 {
2157  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2158 
2159  /*
2160  * Write dirty MultiXact pages to disk. This may result in sync requests
2161  * queued for later handling by ProcessSyncRequests(), as part of the
2162  * checkpoint.
2163  */
2166 
2167  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2168 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1156

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ GetMultiXactIdMembers()

int GetMultiXactIdMembers ( MultiXactId  multi,
MultiXactMember **  xids,
bool  allow_old,
bool  isLockOnly 
)

Definition at line 1223 of file multixact.c.

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

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2506 of file multixact.c.

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

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

Referenced by heapam_relation_set_new_filenode(), vac_update_datfrozenxid(), and vacuum_set_xid_limits().

◆ 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  int pageno;
59 
60  memcpy(&pageno, rec, sizeof(int));
61  appendStringInfo(buf, "%d", 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:439
#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:70
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
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:315
#define XLogRecGetData(decoder)
Definition: xlogreader.h:320
#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 3236 of file multixact.c.

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

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(), 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:916

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 2362 of file multixact.c.

2364 {
2365  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2367  {
2368  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2369  MultiXactState->nextMXact = minMulti;
2370  }
2371  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2372  {
2373  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2374  minMultiOffset);
2375  MultiXactState->nextOffset = minMultiOffset;
2376  }
2377  LWLockRelease(MultiXactGenLock);
2378 }
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3185

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 2387 of file multixact.c.

2388 {
2389  Assert(InRecovery);
2390 
2392  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2393 }
bool InRecovery
Definition: xlogutils.c:52

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 2133 of file multixact.c.

2138 {
2139  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2140  *nextMulti = MultiXactState->nextMXact;
2141  *nextMultiOffset = MultiXactState->nextOffset;
2142  *oldestMulti = MultiXactState->oldestMultiXactId;
2143  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2144  LWLockRelease(MultiXactGenLock);
2145 
2147  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2148  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2149 }
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:337

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 386 of file multixact.c.

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

References Assert(), AssertArg, 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 767 of file multixact.c.

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

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, status(), 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 439 of file multixact.c.

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

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

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdIsRunning()

bool MultiXactIdIsRunning ( MultiXactId  multi,
bool  isLockOnly 
)

Definition at line 551 of file multixact.c.

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

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 3173 of file multixact.c.

3174 {
3175  int32 diff = (int32) (multi1 - multi2);
3176 
3177  return (diff <= 0);
3178 }

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

◆ MultiXactIdSetOldestMember()

void MultiXactIdSetOldestMember ( void  )

Definition at line 625 of file multixact.c.

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

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 2828 of file multixact.c.

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

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3424 of file multixact.c.

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

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3415 of file multixact.c.

3416 {
3417  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3418 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2179 of file multixact.c.

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

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",
1860  "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
1861  MultiXactMemberSLRULock, "pg_multixact/members",
1864  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1865 
1866  /* Initialize our shared state struct */
1867  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1869  &found);
1870  if (!IsUnderPostmaster)
1871  {
1872  Assert(!found);
1873 
1874  /* Make sure we zero out the per-backend state */
1876  }
1877  else
1878  Assert(found);
1879 
1880  /*
1881  * Set up array pointers. Note that perBackendXactIds[0] is wasted space
1882  * since we only use indexes 1..MaxOldestSlot in each array.
1883  */
1886 }
#define MemSet(start, val, len)
Definition: c.h:1008
bool IsUnderPostmaster
Definition: globals.c:112
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:172
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:171
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
static bool MultiXactOffsetPagePrecedes(int page1, int page2)
Definition: multixact.c:3119
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactMemberPagePrecedes(int page1, int page2)
Definition: multixact.c:3139
#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:396
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id, SyncRequestHandler sync_handler)
Definition: slru.c:187
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:156
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:281
@ 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 CreateSharedMemoryAndSemaphores().

◆ 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:540
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:156

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 1655 of file multixact.c.

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

References appendStringInfo(), appendStringInfoChar(), buf, i, initStringInfo(), MemoryContextStrdup(), mxstatus_to_string(), pfree(), status(), 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 1729 of file multixact.c.

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

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

Referenced by PrepareTransaction().

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 743 of file multixact.c.

744 {
745  LWLockAcquire(MultiXactGenLock, LW_SHARED);
748  LWLockRelease(MultiXactGenLock);
749 
750  if (*oldest < FirstMultiXactId)
751  *oldest = FirstMultiXactId;
752  if (*next < FirstMultiXactId)
754 }
static int32 next
Definition: blutils.c:219

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 723 of file multixact.c.

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

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_set_xid_limits(), and vacuum_xid_failsafe_check().

◆ SetMultiXactIdLimit()

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

Definition at line 2213 of file multixact.c.

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

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 2008 of file multixact.c.

2009 {
2012  int pageno;
2013 
2014  /*
2015  * Initialize offset's idea of the latest page number.
2016  */
2017  pageno = MultiXactIdToOffsetPage(multi);
2018  MultiXactOffsetCtl->shared->latest_page_number = pageno;
2019 
2020  /*
2021  * Initialize member's idea of the latest page number.
2022  */
2023  pageno = MXOffsetToMemberPage(offset);
2024  MultiXactMemberCtl->shared->latest_page_number = pageno;
2025 }

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

Referenced by StartupXLOG().

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 2031 of file multixact.c.

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

Referenced by StartupXLOG().

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2944 of file multixact.c.

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

References Assert(), DEBUG1, PGPROC::delayChkpt, 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().