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 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 52 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 49 of file multixact.h.

◆ MultiXactIdIsValid

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

Definition at line 28 of file multixact.h.

◆ SizeOfMultiXactCreate

#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Definition at line 81 of file multixact.h.

◆ SizeOfMultiXactTruncate

#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))

Definition at line 96 of file multixact.h.

◆ XLOG_MULTIXACT_CREATE_ID

#define XLOG_MULTIXACT_CREATE_ID   0x20

Definition at line 70 of file multixact.h.

◆ XLOG_MULTIXACT_TRUNCATE_ID

#define XLOG_MULTIXACT_TRUNCATE_ID   0x30

Definition at line 71 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_MEM_PAGE

#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10

Definition at line 69 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_OFF_PAGE

#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00

Definition at line 68 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 37 of file multixact.h.

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

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1734 of file multixact.c.

1735 {
1736  /*
1737  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1738  * which should only be valid while within a transaction.
1739  *
1740  * We assume that storing a MultiXactId is atomic and so we need not take
1741  * MultiXactGenLock to do this.
1742  */
1745 
1746  /*
1747  * Discard the local MultiXactId cache. Since MXactContext was created as
1748  * a child of TopTransactionContext, we needn't delete it explicitly.
1749  */
1750  MXactContext = NULL;
1752 }
ProcNumber MyProcNumber
Definition: globals.c:87
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:323
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
static dclist_head MXactCache
Definition: multixact.c:322
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
#define InvalidMultiXactId
Definition: multixact.h:24

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

Referenced by AbortTransaction(), and CommitTransaction().

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1762 of file multixact.c.

1763 {
1764  MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
1765 
1766  if (MultiXactIdIsValid(myOldestMember))
1768  &myOldestMember, sizeof(MultiXactId));
1769 }
TransactionId MultiXactId
Definition: c.h:649
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1280
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27

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

Referenced by PrepareTransaction().

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1959 of file multixact.c.

1960 {
1961  int slotno;
1962  LWLock *lock;
1963 
1965  LWLockAcquire(lock, LW_EXCLUSIVE);
1966 
1967  /* Create and zero the first page of the offsets log */
1968  slotno = ZeroMultiXactOffsetPage(0, false);
1969 
1970  /* Make sure it's written out */
1972  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1973 
1974  LWLockRelease(lock);
1975 
1977  LWLockAcquire(lock, LW_EXCLUSIVE);
1978 
1979  /* Create and zero the first page of the members log */
1980  slotno = ZeroMultiXactMemberPage(0, false);
1981 
1982  /* Make sure it's written out */
1984  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1985 
1986  LWLockRelease(lock);
1987 }
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1172
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1785
@ LW_EXCLUSIVE
Definition: lwlock.h:116
static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2015
#define MultiXactMemberCtl
Definition: multixact.c:190
#define MultiXactOffsetCtl
Definition: multixact.c:189
static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
Definition: multixact.c:1999
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:715
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:179
Definition: lwlock.h:41

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

Referenced by BootStrapXLOG().

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2229 of file multixact.c.

2230 {
2231  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2232 
2233  /*
2234  * Write dirty MultiXact pages to disk. This may result in sync requests
2235  * queued for later handling by ProcessSyncRequests(), as part of the
2236  * checkpoint.
2237  */
2240 
2241  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2242 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1305

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ GetMultiXactIdMembers()

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

Definition at line 1239 of file multixact.c.

1241 {
1242  int64 pageno;
1243  int64 prev_pageno;
1244  int entryno;
1245  int slotno;
1246  MultiXactOffset *offptr;
1247  MultiXactOffset offset;
1248  int length;
1249  int truelength;
1250  MultiXactId oldestMXact;
1251  MultiXactId nextMXact;
1252  MultiXactId tmpMXact;
1253  MultiXactOffset nextOffset;
1254  MultiXactMember *ptr;
1255  LWLock *lock;
1256 
1257  debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
1258 
1259  if (!MultiXactIdIsValid(multi) || from_pgupgrade)
1260  {
1261  *members = NULL;
1262  return -1;
1263  }
1264 
1265  /* See if the MultiXactId is in the local cache */
1266  length = mXactCacheGetById(multi, members);
1267  if (length >= 0)
1268  {
1269  debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
1270  mxid_to_string(multi, length, *members));
1271  return length;
1272  }
1273 
1274  /* Set our OldestVisibleMXactId[] entry if we didn't already */
1276 
1277  /*
1278  * If we know the multi is used only for locking and not for updates, then
1279  * we can skip checking if the value is older than our oldest visible
1280  * multi. It cannot possibly still be running.
1281  */
1282  if (isLockOnly &&
1284  {
1285  debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
1286  *members = NULL;
1287  return -1;
1288  }
1289 
1290  /*
1291  * We check known limits on MultiXact before resorting to the SLRU area.
1292  *
1293  * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
1294  * useful; it has already been removed, or will be removed shortly, by
1295  * truncation. If one is passed, an error is raised.
1296  *
1297  * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
1298  * implies undetected ID wraparound has occurred. This raises a hard
1299  * error.
1300  *
1301  * Shared lock is enough here since we aren't modifying any global state.
1302  * Acquire it just long enough to grab the current counter values. We may
1303  * need both nextMXact and nextOffset; see below.
1304  */
1305  LWLockAcquire(MultiXactGenLock, LW_SHARED);
1306 
1307  oldestMXact = MultiXactState->oldestMultiXactId;
1308  nextMXact = MultiXactState->nextMXact;
1309  nextOffset = MultiXactState->nextOffset;
1310 
1311  LWLockRelease(MultiXactGenLock);
1312 
1313  if (MultiXactIdPrecedes(multi, oldestMXact))
1314  ereport(ERROR,
1315  (errcode(ERRCODE_INTERNAL_ERROR),
1316  errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
1317  multi)));
1318 
1319  if (!MultiXactIdPrecedes(multi, nextMXact))
1320  ereport(ERROR,
1321  (errcode(ERRCODE_INTERNAL_ERROR),
1322  errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
1323  multi)));
1324 
1325  /*
1326  * Find out the offset at which we need to start reading MultiXactMembers
1327  * and the number of members in the multixact. We determine the latter as
1328  * the difference between this multixact's starting offset and the next
1329  * one's. However, there are some corner cases to worry about:
1330  *
1331  * 1. This multixact may be the latest one created, in which case there is
1332  * no next one to look at. In this case the nextOffset value we just
1333  * saved is the correct endpoint.
1334  *
1335  * 2. The next multixact may still be in process of being filled in: that
1336  * is, another process may have done GetNewMultiXactId but not yet written
1337  * the offset entry for that ID. In that scenario, it is guaranteed that
1338  * the offset entry for that multixact exists (because GetNewMultiXactId
1339  * won't release MultiXactGenLock until it does) but contains zero
1340  * (because we are careful to pre-zero offset pages). Because
1341  * GetNewMultiXactId will never return zero as the starting offset for a
1342  * multixact, when we read zero as the next multixact's offset, we know we
1343  * have this case. We sleep for a bit and try again.
1344  *
1345  * 3. Because GetNewMultiXactId increments offset zero to offset one to
1346  * handle case #2, there is an ambiguity near the point of offset
1347  * wraparound. If we see next multixact's offset is one, is that our
1348  * multixact's actual endpoint, or did it end at zero with a subsequent
1349  * increment? We handle this using the knowledge that if the zero'th
1350  * member slot wasn't filled, it'll contain zero, and zero isn't a valid
1351  * transaction ID so it can't be a multixact member. Therefore, if we
1352  * read a zero from the members array, just ignore it.
1353  *
1354  * This is all pretty messy, but the mess occurs only in infrequent corner
1355  * cases, so it seems better than holding the MultiXactGenLock for a long
1356  * time on every multixact creation.
1357  */
1358 retry:
1359  pageno = MultiXactIdToOffsetPage(multi);
1360  entryno = MultiXactIdToOffsetEntry(multi);
1361 
1362  /* Acquire the bank lock for the page we need. */
1363  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
1364  LWLockAcquire(lock, LW_EXCLUSIVE);
1365 
1366  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
1367  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1368  offptr += entryno;
1369  offset = *offptr;
1370 
1371  Assert(offset != 0);
1372 
1373  /*
1374  * Use the same increment rule as GetNewMultiXactId(), that is, don't
1375  * handle wraparound explicitly until needed.
1376  */
1377  tmpMXact = multi + 1;
1378 
1379  if (nextMXact == tmpMXact)
1380  {
1381  /* Corner case 1: there is no next multixact */
1382  length = nextOffset - offset;
1383  }
1384  else
1385  {
1386  MultiXactOffset nextMXOffset;
1387 
1388  /* handle wraparound if needed */
1389  if (tmpMXact < FirstMultiXactId)
1390  tmpMXact = FirstMultiXactId;
1391 
1392  prev_pageno = pageno;
1393 
1394  pageno = MultiXactIdToOffsetPage(tmpMXact);
1395  entryno = MultiXactIdToOffsetEntry(tmpMXact);
1396 
1397  if (pageno != prev_pageno)
1398  {
1399  LWLock *newlock;
1400 
1401  /*
1402  * Since we're going to access a different SLRU page, if this page
1403  * falls under a different bank, release the old bank's lock and
1404  * acquire the lock of the new bank.
1405  */
1406  newlock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
1407  if (newlock != lock)
1408  {
1409  LWLockRelease(lock);
1410  LWLockAcquire(newlock, LW_EXCLUSIVE);
1411  lock = newlock;
1412  }
1413  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
1414  }
1415 
1416  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1417  offptr += entryno;
1418  nextMXOffset = *offptr;
1419 
1420  if (nextMXOffset == 0)
1421  {
1422  /* Corner case 2: next multixact is still being filled in */
1423  LWLockRelease(lock);
1425  pg_usleep(1000L);
1426  goto retry;
1427  }
1428 
1429  length = nextMXOffset - offset;
1430  }
1431 
1432  LWLockRelease(lock);
1433  lock = NULL;
1434 
1435  ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
1436 
1437  truelength = 0;
1438  prev_pageno = -1;
1439  for (int i = 0; i < length; i++, offset++)
1440  {
1441  TransactionId *xactptr;
1442  uint32 *flagsptr;
1443  int flagsoff;
1444  int bshift;
1445  int memberoff;
1446 
1447  pageno = MXOffsetToMemberPage(offset);
1448  memberoff = MXOffsetToMemberOffset(offset);
1449 
1450  if (pageno != prev_pageno)
1451  {
1452  LWLock *newlock;
1453 
1454  /*
1455  * Since we're going to access a different SLRU page, if this page
1456  * falls under a different bank, release the old bank's lock and
1457  * acquire the lock of the new bank.
1458  */
1459  newlock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
1460  if (newlock != lock)
1461  {
1462  if (lock)
1463  LWLockRelease(lock);
1464  LWLockAcquire(newlock, LW_EXCLUSIVE);
1465  lock = newlock;
1466  }
1467 
1468  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
1469  prev_pageno = pageno;
1470  }
1471 
1472  xactptr = (TransactionId *)
1473  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1474 
1475  if (!TransactionIdIsValid(*xactptr))
1476  {
1477  /* Corner case 3: we must be looking at unused slot zero */
1478  Assert(offset == 0);
1479  continue;
1480  }
1481 
1482  flagsoff = MXOffsetToFlagsOffset(offset);
1483  bshift = MXOffsetToFlagsBitShift(offset);
1484  flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1485 
1486  ptr[truelength].xid = *xactptr;
1487  ptr[truelength].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
1488  truelength++;
1489  }
1490 
1491  LWLockRelease(lock);
1492 
1493  /* A multixid with zero members should not happen */
1494  Assert(truelength > 0);
1495 
1496  /*
1497  * Copy the result into the local cache.
1498  */
1499  mXactCachePut(multi, truelength, ptr);
1500 
1501  debug_elog3(DEBUG2, "GetMembers: no cache for %s",
1502  mxid_to_string(multi, truelength, ptr));
1503  *members = ptr;
1504  return truelength;
1505 }
unsigned int uint32
Definition: c.h:493
uint32 MultiXactOffset
Definition: c.h:651
uint32 TransactionId
Definition: c.h:639
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#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:1304
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:158
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
Definition: multixact.c:1588
#define MXACT_MEMBER_XACT_BITMASK
Definition: multixact.c:131
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:112
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3234
static void MultiXactIdSetOldestVisible(void)
Definition: multixact.c:681
#define MXOffsetToFlagsBitShift(xid)
Definition: multixact.c:166
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1635
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:162
#define MXOffsetToMemberOffset(xid)
Definition: multixact.c:171
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1703
#define debug_elog3(a, b, c)
Definition: multixact.c:333
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:110
#define debug_elog2(a, b)
Definition: multixact.c:332
#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:488
TransactionId xid
Definition: multixact.h:58
MultiXactStatus status
Definition: multixact.h:59
MultiXactOffset nextOffset
Definition: multixact.c:205
MultiXactId nextMXact
Definition: multixact.c:202
MultiXactId oldestMultiXactId
Definition: multixact.c:215
#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, MyProcNumber, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactId, OldestVisibleMXactId, palloc(), pg_usleep(), SimpleLruGetBankLock(), 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 2585 of file multixact.c.

2586 {
2587  MultiXactId oldestMXact;
2588  MultiXactId nextMXact;
2589  int i;
2590 
2591  /*
2592  * This is the oldest valid value among all the OldestMemberMXactId[] and
2593  * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2594  */
2595  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2596 
2597  /*
2598  * We have to beware of the possibility that nextMXact is in the
2599  * wrapped-around state. We don't fix the counter itself here, but we
2600  * must be sure to use a valid value in our calculation.
2601  */
2602  nextMXact = MultiXactState->nextMXact;
2603  if (nextMXact < FirstMultiXactId)
2604  nextMXact = FirstMultiXactId;
2605 
2606  oldestMXact = nextMXact;
2607  for (i = 0; i < MaxOldestSlot; i++)
2608  {
2609  MultiXactId thisoldest;
2610 
2611  thisoldest = OldestMemberMXactId[i];
2612  if (MultiXactIdIsValid(thisoldest) &&
2613  MultiXactIdPrecedes(thisoldest, oldestMXact))
2614  oldestMXact = thisoldest;
2615  thisoldest = OldestVisibleMXactId[i];
2616  if (MultiXactIdIsValid(thisoldest) &&
2617  MultiXactIdPrecedes(thisoldest, oldestMXact))
2618  oldestMXact = thisoldest;
2619  }
2620 
2621  LWLockRelease(MultiXactGenLock);
2622 
2623  return oldestMXact;
2624 }
#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_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:491
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:69
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:68
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:71
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:70
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:75
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:78
MultiXactOffset moff
Definition: multixact.h:76
MultiXactId endTruncOff
Definition: multixact.h:89
MultiXactOffset startTruncMemb
Definition: multixact.h:92
MultiXactOffset endTruncMemb
Definition: multixact.h:93
MultiXactId startTruncOff
Definition: multixact.h:88
#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 3311 of file multixact.c.

3312 {
3313  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3314 
3315  /* Backup blocks are not used in multixact records */
3316  Assert(!XLogRecHasAnyBlockRefs(record));
3317 
3318  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3319  {
3320  int64 pageno;
3321  int slotno;
3322  LWLock *lock;
3323 
3324  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3325 
3326  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
3327  LWLockAcquire(lock, LW_EXCLUSIVE);
3328 
3329  slotno = ZeroMultiXactOffsetPage(pageno, false);
3331  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3332 
3333  LWLockRelease(lock);
3334  }
3335  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3336  {
3337  int64 pageno;
3338  int slotno;
3339  LWLock *lock;
3340 
3341  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3342 
3343  lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
3344  LWLockAcquire(lock, LW_EXCLUSIVE);
3345 
3346  slotno = ZeroMultiXactMemberPage(pageno, false);
3348  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3349 
3350  LWLockRelease(lock);
3351  }
3352  else if (info == XLOG_MULTIXACT_CREATE_ID)
3353  {
3354  xl_multixact_create *xlrec =
3355  (xl_multixact_create *) XLogRecGetData(record);
3356  TransactionId max_xid;
3357  int i;
3358 
3359  /* Store the data back into the SLRU files */
3360  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3361  xlrec->members);
3362 
3363  /* Make sure nextMXact/nextOffset are beyond what this record has */
3364  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3365  xlrec->moff + xlrec->nmembers);
3366 
3367  /*
3368  * Make sure nextXid is beyond any XID mentioned in the record. This
3369  * should be unnecessary, since any XID found here ought to have other
3370  * evidence in the XLOG, but let's be safe.
3371  */
3372  max_xid = XLogRecGetXid(record);
3373  for (i = 0; i < xlrec->nmembers; i++)
3374  {
3375  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3376  max_xid = xlrec->members[i].xid;
3377  }
3378 
3380  }
3381  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3382  {
3383  xl_multixact_truncate xlrec;
3384  int64 pageno;
3385 
3386  memcpy(&xlrec, XLogRecGetData(record),
3388 
3389  elog(DEBUG1, "replaying multixact truncation: "
3390  "offsets [%u, %u), offsets segments [%x, %x), "
3391  "members [%u, %u), members segments [%x, %x)",
3392  xlrec.startTruncOff, xlrec.endTruncOff,
3395  xlrec.startTruncMemb, xlrec.endTruncMemb,
3398 
3399  /* should not be required, but more than cheap enough */
3400  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3401 
3402  /*
3403  * Advance the horizon values, so they're current at the end of
3404  * recovery.
3405  */
3406  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3407 
3409 
3410  /*
3411  * During XLOG replay, latest_page_number isn't necessarily set up
3412  * yet; insert a suitable value to bypass the sanity test in
3413  * SimpleLruTruncate.
3414  */
3415  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3416  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3417  pageno);
3419 
3420  LWLockRelease(MultiXactTruncationLock);
3421  }
3422  else
3423  elog(PANIC, "multixact_redo: unknown op code %u", info);
3424 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:480
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:224
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2994
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2966
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2287
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:862
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:159
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2436
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:114
#define SizeOfMultiXactTruncate
Definition: multixact.h:96
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(), SimpleLruGetBankLock(), 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 1861 of file multixact.c.

1863 {
1864  multixact_twophase_postcommit(xid, info, recdata, len);
1865 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1846
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 1846 of file multixact.c.

1848 {
1849  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, true);
1850 
1851  Assert(len == sizeof(MultiXactId));
1852 
1853  OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1854 }
int ProcNumber
Definition: procnumber.h:24
ProcNumber TwoPhaseGetDummyProcNumber(TransactionId xid, bool lock_held)
Definition: twophase.c:903

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

Referenced by multixact_twophase_postabort().

◆ multixact_twophase_recover()

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

Definition at line 1825 of file multixact.c.

1827 {
1828  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1829  MultiXactId oldestMember;
1830 
1831  /*
1832  * Get the oldest member XID from the state file record, and set it in the
1833  * OldestMemberMXactId slot reserved for this prepared transaction.
1834  */
1835  Assert(len == sizeof(MultiXactId));
1836  oldestMember = *((MultiXactId *) recdata);
1837 
1838  OldestMemberMXactId[dummyProcNumber] = oldestMember;
1839 }

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2436 of file multixact.c.

2438 {
2439  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2441  {
2442  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2443  MultiXactState->nextMXact = minMulti;
2444  }
2445  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2446  {
2447  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2448  minMultiOffset);
2449  MultiXactState->nextOffset = minMultiOffset;
2450  }
2451  LWLockRelease(MultiXactGenLock);
2452 }
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3260

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

2462 {
2463  Assert(InRecovery);
2464 
2466  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2467 }
bool InRecovery
Definition: xlogutils.c:50

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

2212 {
2213  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2214  *nextMulti = MultiXactState->nextMXact;
2215  *nextMultiOffset = MultiXactState->nextOffset;
2216  *oldestMulti = MultiXactState->oldestMultiXactId;
2217  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2218  LWLockRelease(MultiXactGenLock);
2219 
2221  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2222  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2223 }
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:336

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

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

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

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 766 of file multixact.c.

767 {
768  MultiXactId multi;
769  MultiXactOffset offset;
770  xl_multixact_create xlrec;
771 
772  debug_elog3(DEBUG2, "Create: %s",
773  mxid_to_string(InvalidMultiXactId, nmembers, members));
774 
775  /*
776  * See if the same set of members already exists in our cache; if so, just
777  * re-use that MultiXactId. (Note: it might seem that looking in our
778  * cache is insufficient, and we ought to search disk to see if a
779  * duplicate definition already exists. But since we only ever create
780  * MultiXacts containing our own XID, in most cases any such MultiXacts
781  * were in fact created by us, and so will be in our cache. There are
782  * corner cases where someone else added us to a MultiXact without our
783  * knowledge, but it's not worth checking for.)
784  */
785  multi = mXactCacheGetBySet(nmembers, members);
786  if (MultiXactIdIsValid(multi))
787  {
788  debug_elog2(DEBUG2, "Create: in cache!");
789  return multi;
790  }
791 
792  /* Verify that there is a single update Xid among the given members. */
793  {
794  int i;
795  bool has_update = false;
796 
797  for (i = 0; i < nmembers; i++)
798  {
799  if (ISUPDATE_from_mxstatus(members[i].status))
800  {
801  if (has_update)
802  elog(ERROR, "new multixact has more than one updating member: %s",
803  mxid_to_string(InvalidMultiXactId, nmembers, members));
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:151
static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
Definition: multixact.c:972
static MultiXactId mXactCacheGetBySet(int nmembers, MultiXactMember *members)
Definition: multixact.c:1545
#define ISUPDATE_from_mxstatus(status)
Definition: multixact.h:52
#define SizeOfMultiXactCreate
Definition: multixact.h:81
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:364
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogBeginInsert(void)
Definition: xloginsert.c:149

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

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

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

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

3249 {
3250  int32 diff = (int32) (multi1 - multi2);
3251 
3252  return (diff <= 0);
3253 }

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

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

References DEBUG2, debug_elog4, FirstMultiXactId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactState, MyProcNumber, 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 2903 of file multixact.c.

2904 {
2905  MultiXactOffset members;
2906  uint32 multixacts;
2907  uint32 victim_multixacts;
2908  double fraction;
2909 
2910  /* If we can't determine member space utilization, assume the worst. */
2911  if (!ReadMultiXactCounts(&multixacts, &members))
2912  return 0;
2913 
2914  /* If member space utilization is low, no special action is required. */
2915  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2917 
2918  /*
2919  * Compute a target for relminmxid advancement. The number of multixacts
2920  * we try to eliminate from the system is based on how far we are past
2921  * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2922  */
2923  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2925  victim_multixacts = multixacts * fraction;
2926 
2927  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2928  if (victim_multixacts > multixacts)
2929  return 0;
2930  return multixacts - victim_multixacts;
2931 }
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:126
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:176
static bool ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
Definition: multixact.c:2851
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:177

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

3502 {
3503  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3504 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1814

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3492 of file multixact.c.

3493 {
3494  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3495 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2253 of file multixact.c.

2255 {
2256  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2257  nextMulti, nextMultiOffset);
2258  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2259  MultiXactState->nextMXact = nextMulti;
2260  MultiXactState->nextOffset = nextMultiOffset;
2261  LWLockRelease(MultiXactGenLock);
2262 
2263  /*
2264  * During a binary upgrade, make sure that the offsets SLRU is large
2265  * enough to contain the next value that would be created.
2266  *
2267  * We need to do this pretty early during the first startup in binary
2268  * upgrade mode: before StartupMultiXact() in fact, because this routine
2269  * is called even before that by StartupXLOG(). And we can't do it
2270  * earlier than at this point, because during that first call of this
2271  * routine we determine the MultiXactState->nextMXact value that
2272  * MaybeExtendOffsetSlru needs.
2273  */
2274  if (IsBinaryUpgrade)
2276 }
bool IsBinaryUpgrade
Definition: globals.c:118
static void MaybeExtendOffsetSlru(void)
Definition: multixact.c:2043

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

1891 {
1892  bool found;
1893 
1894  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1895 
1898 
1900  "multixact_offset", multixact_offset_buffers, 0,
1901  "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1904  false);
1907  "multixact_member", multixact_member_buffers, 0,
1908  "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1911  false);
1912  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1913 
1914  /* Initialize our shared state struct */
1915  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1917  &found);
1918  if (!IsUnderPostmaster)
1919  {
1920  Assert(!found);
1921 
1922  /* Make sure we zero out the per-backend state */
1924  }
1925  else
1926  Assert(found);
1927 
1928  /*
1929  * Set up array pointers.
1930  */
1933 }
#define MemSet(start, val, len)
Definition: c.h:1007
int multixact_offset_buffers
Definition: globals.c:164
bool IsUnderPostmaster
Definition: globals.c:117
int multixact_member_buffers
Definition: globals.c:163
@ LWTRANCHE_MULTIXACTOFFSET_SLRU
Definition: lwlock.h:214
@ LWTRANCHE_MULTIXACTMEMBER_SLRU
Definition: lwlock.h:213
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:185
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:184
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3214
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:108
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3194
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition: slru.c:238
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:203
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:282
@ 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_MULTIXACTMEMBER_SLRU, LWTRANCHE_MULTIXACTOFFSET_BUFFER, LWTRANCHE_MULTIXACTOFFSET_SLRU, MaxOldestSlot, MemSet, multixact_member_buffers, multixact_offset_buffers, MULTIXACT_OFFSETS_PER_PAGE, MultiXactMemberCtl, MultiXactMemberPagePrecedes(), MultiXactOffsetCtl, MultiXactOffsetPagePrecedes(), MultiXactState, 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 1873 of file multixact.c.

1874 {
1875  Size size;
1876 
1877  /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1878 #define SHARED_MULTIXACT_STATE_SIZE \
1879  add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1880  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1881 
1885 
1886  return size;
1887 }
size_t Size
Definition: c.h:592
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
static pg_noinline void Size size
Definition: slab.c:607
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:184

References add_size(), multixact_member_buffers, multixact_offset_buffers, SHARED_MULTIXACT_STATE_SIZE, SimpleLruShmemSize(), and size.

Referenced by CalculateShmemSize().

◆ mxid_to_string()

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

Definition at line 1703 of file multixact.c.

1704 {
1705  static char *str = NULL;
1707  int i;
1708 
1709  if (str != NULL)
1710  pfree(str);
1711 
1712  initStringInfo(&buf);
1713 
1714  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1715  mxstatus_to_string(members[0].status));
1716 
1717  for (i = 1; i < nmembers; i++)
1718  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1719  mxstatus_to_string(members[i].status));
1720 
1721  appendStringInfoChar(&buf, ']');
1723  pfree(buf.data);
1724  return str;
1725 }
MemoryContext TopMemoryContext
Definition: mcxt.c:137
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1670
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 1776 of file multixact.c.

1777 {
1778  MultiXactId myOldestMember;
1779 
1780  /*
1781  * Transfer our OldestMemberMXactId value to the slot reserved for the
1782  * prepared transaction.
1783  */
1784  myOldestMember = OldestMemberMXactId[MyProcNumber];
1785  if (MultiXactIdIsValid(myOldestMember))
1786  {
1787  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1788 
1789  /*
1790  * Even though storing MultiXactId is atomic, acquire lock to make
1791  * sure others see both changes, not just the reset of the slot of the
1792  * current backend. Using a volatile pointer might suffice, but this
1793  * isn't a hot spot.
1794  */
1795  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1796 
1797  OldestMemberMXactId[dummyProcNumber] = myOldestMember;
1799 
1800  LWLockRelease(MultiXactGenLock);
1801  }
1802 
1803  /*
1804  * We don't need to transfer OldestVisibleMXactId value, because the
1805  * transaction is not going to be looking at any more multixacts once it's
1806  * prepared.
1807  *
1808  * We assume that storing a MultiXactId is atomic and so we need not take
1809  * MultiXactGenLock to do this.
1810  */
1812 
1813  /*
1814  * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1815  */
1816  MXactContext = NULL;
1818 }

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

Referenced by PrepareTransaction().

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 742 of file multixact.c.

743 {
744  LWLockAcquire(MultiXactGenLock, LW_SHARED);
747  LWLockRelease(MultiXactGenLock);
748 
749  if (*oldest < FirstMultiXactId)
750  *oldest = FirstMultiXactId;
751  if (*next < FirstMultiXactId)
753 }
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 722 of file multixact.c.

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

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

2289 {
2290  MultiXactId multiVacLimit;
2291  MultiXactId multiWarnLimit;
2292  MultiXactId multiStopLimit;
2293  MultiXactId multiWrapLimit;
2294  MultiXactId curMulti;
2295  bool needs_offset_vacuum;
2296 
2297  Assert(MultiXactIdIsValid(oldest_datminmxid));
2298 
2299  /*
2300  * We pretend that a wrap will happen halfway through the multixact ID
2301  * space, but that's not really true, because multixacts wrap differently
2302  * from transaction IDs. Note that, separately from any concern about
2303  * multixact IDs wrapping, we must ensure that multixact members do not
2304  * wrap. Limits for that are set in SetOffsetVacuumLimit, not here.
2305  */
2306  multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
2307  if (multiWrapLimit < FirstMultiXactId)
2308  multiWrapLimit += FirstMultiXactId;
2309 
2310  /*
2311  * We'll refuse to continue assigning MultiXactIds once we get within 3M
2312  * multi of data loss. See SetTransactionIdLimit.
2313  */
2314  multiStopLimit = multiWrapLimit - 3000000;
2315  if (multiStopLimit < FirstMultiXactId)
2316  multiStopLimit -= FirstMultiXactId;
2317 
2318  /*
2319  * We'll start complaining loudly when we get within 40M multis of data
2320  * loss. This is kind of arbitrary, but if you let your gas gauge get
2321  * down to 2% of full, would you be looking for the next gas station? We
2322  * need to be fairly liberal about this number because there are lots of
2323  * scenarios where most transactions are done by automatic clients that
2324  * won't pay attention to warnings. (No, we're not gonna make this
2325  * configurable. If you know enough to configure it, you know enough to
2326  * not get in this kind of trouble in the first place.)
2327  */
2328  multiWarnLimit = multiWrapLimit - 40000000;
2329  if (multiWarnLimit < FirstMultiXactId)
2330  multiWarnLimit -= FirstMultiXactId;
2331 
2332  /*
2333  * We'll start trying to force autovacuums when oldest_datminmxid gets to
2334  * be more than autovacuum_multixact_freeze_max_age mxids old.
2335  *
2336  * Note: autovacuum_multixact_freeze_max_age is a PGC_POSTMASTER parameter
2337  * so that we don't have to worry about dealing with on-the-fly changes in
2338  * its value. See SetTransactionIdLimit.
2339  */
2340  multiVacLimit = oldest_datminmxid + autovacuum_multixact_freeze_max_age;
2341  if (multiVacLimit < FirstMultiXactId)
2342  multiVacLimit += FirstMultiXactId;
2343 
2344  /* Grab lock for just long enough to set the new limit values */
2345  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2346  MultiXactState->oldestMultiXactId = oldest_datminmxid;
2347  MultiXactState->oldestMultiXactDB = oldest_datoid;
2348  MultiXactState->multiVacLimit = multiVacLimit;
2349  MultiXactState->multiWarnLimit = multiWarnLimit;
2350  MultiXactState->multiStopLimit = multiStopLimit;
2351  MultiXactState->multiWrapLimit = multiWrapLimit;
2352  curMulti = MultiXactState->nextMXact;
2353  LWLockRelease(MultiXactGenLock);
2354 
2355  /* Log the info */
2356  ereport(DEBUG1,
2357  (errmsg_internal("MultiXactId wrap limit is %u, limited by database with OID %u",
2358  multiWrapLimit, oldest_datoid)));
2359 
2360  /*
2361  * Computing the actual limits is only possible once the data directory is
2362  * in a consistent state. There's no need to compute the limits while
2363  * still replaying WAL - no decisions about new multis are made even
2364  * though multixact creations might be replayed. So we'll only do further
2365  * checks after TrimMultiXact() has been called.
2366  */
2368  return;
2369 
2370  Assert(!InRecovery);
2371 
2372  /* Set limits for offset vacuum. */
2373  needs_offset_vacuum = SetOffsetVacuumLimit(is_startup);
2374 
2375  /*
2376  * If past the autovacuum force point, immediately signal an autovac
2377  * request. The reason for this is that autovac only processes one
2378  * database per invocation. Once it's finished cleaning up the oldest
2379  * database, it'll call here, and we'll signal the postmaster to start
2380  * another iteration immediately if there are still any old databases.
2381  */
2382  if ((MultiXactIdPrecedes(multiVacLimit, curMulti) ||
2383  needs_offset_vacuum) && IsUnderPostmaster)
2385 
2386  /* Give an immediate warning if past the wrap warn point */
2387  if (MultiXactIdPrecedes(multiWarnLimit, curMulti))
2388  {
2389  char *oldest_datname;
2390 
2391  /*
2392  * We can be called when not inside a transaction, for example during
2393  * StartupXLOG(). In such a case we cannot do database access, so we
2394  * must just report the oldest DB's OID.
2395  *
2396  * Note: it's also possible that get_database_name fails and returns
2397  * NULL, for example because the database just got dropped. We'll
2398  * still warn, even though the warning might now be unnecessary.
2399  */
2400  if (IsTransactionState())
2401  oldest_datname = get_database_name(oldest_datoid);
2402  else
2403  oldest_datname = NULL;
2404 
2405  if (oldest_datname)
2406  ereport(WARNING,
2407  (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
2408  "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
2409  multiWrapLimit - curMulti,
2410  oldest_datname,
2411  multiWrapLimit - curMulti),
2412  errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2413  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2414  else
2415  ereport(WARNING,
2416  (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
2417  "database with OID %u must be vacuumed before %u more MultiXactIds are used",
2418  multiWrapLimit - curMulti,
2419  oldest_datoid,
2420  multiWrapLimit - curMulti),
2421  errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2422  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2423  }
2424 }
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3153
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1182
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1159
int errhint(const char *fmt,...)
Definition: elog.c:1319
#define WARNING
Definition: elog.h:36
static bool SetOffsetVacuumLimit(bool is_startup)
Definition: multixact.c:2638
#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:230
MultiXactId multiStopLimit
Definition: multixact.c:229
MultiXactId multiWarnLimit
Definition: multixact.c:228
MultiXactId multiVacLimit
Definition: multixact.c:227
bool IsTransactionState(void)
Definition: xact.c:379

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

2079 {
2082  int64 pageno;
2083 
2084  /*
2085  * Initialize offset's idea of the latest page number.
2086  */
2087  pageno = MultiXactIdToOffsetPage(multi);
2088  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2089  pageno);
2090 
2091  /*
2092  * Initialize member's idea of the latest page number.
2093  */
2094  pageno = MXOffsetToMemberPage(offset);
2095  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2096  pageno);
2097 }

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

2104 {
2105  MultiXactId nextMXact;
2106  MultiXactOffset offset;
2107  MultiXactId oldestMXact;
2108  Oid oldestMXactDB;
2109  int64 pageno;
2110  int entryno;
2111  int flagsoff;
2112 
2113  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2114  nextMXact = MultiXactState->nextMXact;
2115  offset = MultiXactState->nextOffset;
2116  oldestMXact = MultiXactState->oldestMultiXactId;
2117  oldestMXactDB = MultiXactState->oldestMultiXactDB;
2118  LWLockRelease(MultiXactGenLock);
2119 
2120  /* Clean up offsets state */
2121 
2122  /*
2123  * (Re-)Initialize our idea of the latest page number for offsets.
2124  */
2125  pageno = MultiXactIdToOffsetPage(nextMXact);
2126  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2127  pageno);
2128 
2129  /*
2130  * Zero out the remainder of the current offsets page. See notes in
2131  * TrimCLOG() for background. Unlike CLOG, some WAL record covers every
2132  * pg_multixact SLRU mutation. Since, also unlike CLOG, we ignore the WAL
2133  * rule "write xlog before data," nextMXact successors may carry obsolete,
2134  * nonzero offset values. Zero those so case 2 of GetMultiXactIdMembers()
2135  * operates normally.
2136  */
2137  entryno = MultiXactIdToOffsetEntry(nextMXact);
2138  if (entryno != 0)
2139  {
2140  int slotno;
2141  MultiXactOffset *offptr;
2143 
2144  LWLockAcquire(lock, LW_EXCLUSIVE);
2145  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2146  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2147  offptr += entryno;
2148 
2149  MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
2150 
2151  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2152  LWLockRelease(lock);
2153  }
2154 
2155  /*
2156  * And the same for members.
2157  *
2158  * (Re-)Initialize our idea of the latest page number for members.
2159  */
2160  pageno = MXOffsetToMemberPage(offset);
2161  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2162  pageno);
2163 
2164  /*
2165  * Zero out the remainder of the current members page. See notes in
2166  * TrimCLOG() for motivation.
2167  */
2168  flagsoff = MXOffsetToFlagsOffset(offset);
2169  if (flagsoff != 0)
2170  {
2171  int slotno;
2172  TransactionId *xidptr;
2173  int memberoff;
2175 
2176  LWLockAcquire(lock, LW_EXCLUSIVE);
2177  memberoff = MXOffsetToMemberOffset(offset);
2178  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2179  xidptr = (TransactionId *)
2180  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2181 
2182  MemSet(xidptr, 0, BLCKSZ - memberoff);
2183 
2184  /*
2185  * Note: we don't need to zero out the flag bits in the remaining
2186  * members of the current group, because they are always reset before
2187  * writing.
2188  */
2189 
2190  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2191  LWLockRelease(lock);
2192  }
2193 
2194  /* signal that we're officially up */
2195  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2197  LWLockRelease(MultiXactGenLock);
2198 
2199  /* Now compute how far away the next members wraparound is. */
2200  SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2201 }
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(), SimpleLruGetBankLock(), and SimpleLruReadPage().

Referenced by StartupXLOG().

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  newOldestMulti,
Oid  newOldestMultiDB 
)

Definition at line 3019 of file multixact.c.

3020 {
3021  MultiXactId oldestMulti;
3022  MultiXactId nextMulti;
3023  MultiXactOffset newOldestOffset;
3024  MultiXactOffset oldestOffset;
3025  MultiXactOffset nextOffset;
3026  mxtruncinfo trunc;
3027  MultiXactId earliest;
3028 
3031 
3032  /*
3033  * We can only allow one truncation to happen at once. Otherwise parts of
3034  * members might vanish while we're doing lookups or similar. There's no
3035  * need to have an interlock with creating new multis or such, since those
3036  * are constrained by the limits (which only grow, never shrink).
3037  */
3038  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3039 
3040  LWLockAcquire(MultiXactGenLock, LW_SHARED);
3041  nextMulti = MultiXactState->nextMXact;
3042  nextOffset = MultiXactState->nextOffset;
3043  oldestMulti = MultiXactState->oldestMultiXactId;
3044  LWLockRelease(MultiXactGenLock);
3045  Assert(MultiXactIdIsValid(oldestMulti));
3046 
3047  /*
3048  * Make sure to only attempt truncation if there's values to truncate
3049  * away. In normal processing values shouldn't go backwards, but there's
3050  * some corner cases (due to bugs) where that's possible.
3051  */
3052  if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
3053  {
3054  LWLockRelease(MultiXactTruncationLock);
3055  return;
3056  }
3057 
3058  /*
3059  * Note we can't just plow ahead with the truncation; it's possible that
3060  * there are no segments to truncate, which is a problem because we are
3061  * going to attempt to read the offsets page to determine where to
3062  * truncate the members SLRU. So we first scan the directory to determine
3063  * the earliest offsets page number that we can read without error.
3064  *
3065  * When nextMXact is less than one segment away from multiWrapLimit,
3066  * SlruScanDirCbFindEarliest can find some early segment other than the
3067  * actual earliest. (MultiXactOffsetPagePrecedes(EARLIEST, LATEST)
3068  * returns false, because not all pairs of entries have the same answer.)
3069  * That can also arise when an earlier truncation attempt failed unlink()
3070  * or returned early from this function. The only consequence is
3071  * returning early, which wastes space that we could have liberated.
3072  *
3073  * NB: It's also possible that the page that oldestMulti is on has already
3074  * been truncated away, and we crashed before updating oldestMulti.
3075  */
3076  trunc.earliestExistingPage = -1;
3079  if (earliest < FirstMultiXactId)
3080  earliest = FirstMultiXactId;
3081 
3082  /* If there's nothing to remove, we can bail out early. */
3083  if (MultiXactIdPrecedes(oldestMulti, earliest))
3084  {
3085  LWLockRelease(MultiXactTruncationLock);
3086  return;
3087  }
3088 
3089  /*
3090  * First, compute the safe truncation point for MultiXactMember. This is
3091  * the starting offset of the oldest multixact.
3092  *
3093  * Hopefully, find_multixact_start will always work here, because we've
3094  * already checked that it doesn't precede the earliest MultiXact on disk.
3095  * But if it fails, don't truncate anything, and log a message.
3096  */
3097  if (oldestMulti == nextMulti)
3098  {
3099  /* there are NO MultiXacts */
3100  oldestOffset = nextOffset;
3101  }
3102  else if (!find_multixact_start(oldestMulti, &oldestOffset))
3103  {
3104  ereport(LOG,
3105  (errmsg("oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
3106  oldestMulti, earliest)));
3107  LWLockRelease(MultiXactTruncationLock);
3108  return;
3109  }
3110 
3111  /*
3112  * Secondly compute up to where to truncate. Lookup the corresponding
3113  * member offset for newOldestMulti for that.
3114  */
3115  if (newOldestMulti == nextMulti)
3116  {
3117  /* there are NO MultiXacts */
3118  newOldestOffset = nextOffset;
3119  }
3120  else if (!find_multixact_start(newOldestMulti, &newOldestOffset))
3121  {
3122  ereport(LOG,
3123  (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
3124  newOldestMulti)));
3125  LWLockRelease(MultiXactTruncationLock);
3126  return;
3127  }
3128 
3129  elog(DEBUG1, "performing multixact truncation: "
3130  "offsets [%u, %u), offsets segments [%x, %x), "
3131  "members [%u, %u), members segments [%x, %x)",
3132  oldestMulti, newOldestMulti,
3133  MultiXactIdToOffsetSegment(oldestMulti),
3134  MultiXactIdToOffsetSegment(newOldestMulti),
3135  oldestOffset, newOldestOffset,
3136  MXOffsetToMemberSegment(oldestOffset),
3137  MXOffsetToMemberSegment(newOldestOffset));
3138 
3139  /*
3140  * Do truncation, and the WAL logging of the truncation, in a critical
3141  * section. That way offsets/members cannot get out of sync anymore, i.e.
3142  * once consistent the newOldestMulti will always exist in members, even
3143  * if we crashed in the wrong moment.
3144  */
3146 
3147  /*
3148  * Prevent checkpoints from being scheduled concurrently. This is critical
3149  * because otherwise a truncation record might not be replayed after a
3150  * crash/basebackup, even though the state of the data directory would
3151  * require it.
3152  */
3155 
3156  /* WAL log truncation */
3157  WriteMTruncateXlogRec(newOldestMultiDB,
3158  oldestMulti, newOldestMulti,
3159  oldestOffset, newOldestOffset);
3160 
3161  /*
3162  * Update in-memory limits before performing the truncation, while inside
3163  * the critical section: Have to do it before truncation, to prevent
3164  * concurrent lookups of those values. Has to be inside the critical
3165  * section as otherwise a future call to this function would error out,
3166  * while looking up the oldest member in offsets, if our caller crashes
3167  * before updating the limits.
3168  */
3169  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
3170  MultiXactState->oldestMultiXactId = newOldestMulti;
3171  MultiXactState->oldestMultiXactDB = newOldestMultiDB;
3172  LWLockRelease(MultiXactGenLock);
3173 
3174  /* First truncate members */
3175  PerformMembersTruncation(oldestOffset, newOldestOffset);
3176 
3177  /* Then offsets */
3178  PerformOffsetsTruncation(oldestMulti, newOldestMulti);
3179 
3181 
3182  END_CRIT_SECTION();
3183  LWLockRelease(MultiXactTruncationLock);
3184 }
#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:3286
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition: multixact.c:2813
static bool SlruScanDirCbFindEarliest(SlruCtl ctl, char *filename, int64 segpage, void *data)
Definition: multixact.c:2943
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3248
#define DELAY_CHKPT_START
Definition: proc.h:114
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1774
PGPROC * MyProc
Definition: proc.c:66
int delayChkptFlags
Definition: proc.h:236
int64 earliestExistingPage
Definition: multixact.c:2935
bool RecoveryInProgress(void)
Definition: xlog.c:6201

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().