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

1801 {
1802  /*
1803  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1804  * which should only be valid while within a transaction.
1805  *
1806  * We assume that storing a MultiXactId is atomic and so we need not take
1807  * MultiXactGenLock to do this.
1808  */
1811 
1812  /*
1813  * Discard the local MultiXactId cache. Since MXactContext was created as
1814  * a child of TopTransactionContext, we needn't delete it explicitly.
1815  */
1816  MXactContext = NULL;
1818 }
ProcNumber MyProcNumber
Definition: globals.c:88
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:371
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:341
static dclist_head MXactCache
Definition: multixact.c:370
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:340
#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 1828 of file multixact.c.

1829 {
1830  MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
1831 
1832  if (MultiXactIdIsValid(myOldestMember))
1834  &myOldestMember, sizeof(MultiXactId));
1835 }
TransactionId MultiXactId
Definition: c.h:662
#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 2026 of file multixact.c.

2027 {
2028  int slotno;
2029  LWLock *lock;
2030 
2032  LWLockAcquire(lock, LW_EXCLUSIVE);
2033 
2034  /* Create and zero the first page of the offsets log */
2035  slotno = ZeroMultiXactOffsetPage(0, false);
2036 
2037  /* Make sure it's written out */
2039  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
2040 
2041  LWLockRelease(lock);
2042 
2044  LWLockAcquire(lock, LW_EXCLUSIVE);
2045 
2046  /* Create and zero the first page of the members log */
2047  slotno = ZeroMultiXactMemberPage(0, false);
2048 
2049  /* Make sure it's written out */
2051  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
2052 
2053  LWLockRelease(lock);
2054 }
#define Assert(condition)
Definition: c.h:858
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2082
#define MultiXactMemberCtl
Definition: multixact.c:232
#define MultiXactOffsetCtl
Definition: multixact.c:231
static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2066
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:729
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:178
Definition: lwlock.h:42

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

Referenced by BootStrapXLOG().

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2296 of file multixact.c.

2297 {
2298  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2299 
2300  /*
2301  * Write dirty MultiXact pages to disk. This may result in sync requests
2302  * queued for later handling by ProcessSyncRequests(), as part of the
2303  * checkpoint.
2304  */
2307 
2308  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2309 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1319

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ GetMultiXactIdMembers()

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

Definition at line 1293 of file multixact.c.

1295 {
1296  int64 pageno;
1297  int64 prev_pageno;
1298  int entryno;
1299  int slotno;
1300  MultiXactOffset *offptr;
1301  MultiXactOffset offset;
1302  int length;
1303  int truelength;
1304  MultiXactId oldestMXact;
1305  MultiXactId nextMXact;
1306  MultiXactId tmpMXact;
1307  MultiXactOffset nextOffset;
1308  MultiXactMember *ptr;
1309  LWLock *lock;
1310  bool slept = false;
1311 
1312  debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
1313 
1314  if (!MultiXactIdIsValid(multi) || from_pgupgrade)
1315  {
1316  *members = NULL;
1317  return -1;
1318  }
1319 
1320  /* See if the MultiXactId is in the local cache */
1321  length = mXactCacheGetById(multi, members);
1322  if (length >= 0)
1323  {
1324  debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
1325  mxid_to_string(multi, length, *members));
1326  return length;
1327  }
1328 
1329  /* Set our OldestVisibleMXactId[] entry if we didn't already */
1331 
1332  /*
1333  * If we know the multi is used only for locking and not for updates, then
1334  * we can skip checking if the value is older than our oldest visible
1335  * multi. It cannot possibly still be running.
1336  */
1337  if (isLockOnly &&
1339  {
1340  debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
1341  *members = NULL;
1342  return -1;
1343  }
1344 
1345  /*
1346  * We check known limits on MultiXact before resorting to the SLRU area.
1347  *
1348  * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
1349  * useful; it has already been removed, or will be removed shortly, by
1350  * truncation. If one is passed, an error is raised.
1351  *
1352  * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
1353  * implies undetected ID wraparound has occurred. This raises a hard
1354  * error.
1355  *
1356  * Shared lock is enough here since we aren't modifying any global state.
1357  * Acquire it just long enough to grab the current counter values. We may
1358  * need both nextMXact and nextOffset; see below.
1359  */
1360  LWLockAcquire(MultiXactGenLock, LW_SHARED);
1361 
1362  oldestMXact = MultiXactState->oldestMultiXactId;
1363  nextMXact = MultiXactState->nextMXact;
1364  nextOffset = MultiXactState->nextOffset;
1365 
1366  LWLockRelease(MultiXactGenLock);
1367 
1368  if (MultiXactIdPrecedes(multi, oldestMXact))
1369  ereport(ERROR,
1370  (errcode(ERRCODE_INTERNAL_ERROR),
1371  errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
1372  multi)));
1373 
1374  if (!MultiXactIdPrecedes(multi, nextMXact))
1375  ereport(ERROR,
1376  (errcode(ERRCODE_INTERNAL_ERROR),
1377  errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
1378  multi)));
1379 
1380  /*
1381  * Find out the offset at which we need to start reading MultiXactMembers
1382  * and the number of members in the multixact. We determine the latter as
1383  * the difference between this multixact's starting offset and the next
1384  * one's. However, there are some corner cases to worry about:
1385  *
1386  * 1. This multixact may be the latest one created, in which case there is
1387  * no next one to look at. In this case the nextOffset value we just
1388  * saved is the correct endpoint.
1389  *
1390  * 2. The next multixact may still be in process of being filled in: that
1391  * is, another process may have done GetNewMultiXactId but not yet written
1392  * the offset entry for that ID. In that scenario, it is guaranteed that
1393  * the offset entry for that multixact exists (because GetNewMultiXactId
1394  * won't release MultiXactGenLock until it does) but contains zero
1395  * (because we are careful to pre-zero offset pages). Because
1396  * GetNewMultiXactId will never return zero as the starting offset for a
1397  * multixact, when we read zero as the next multixact's offset, we know we
1398  * have this case. We handle this by sleeping on the condition variable
1399  * we have just for this; the process in charge will signal the CV as soon
1400  * as it has finished writing the multixact offset.
1401  *
1402  * 3. Because GetNewMultiXactId increments offset zero to offset one to
1403  * handle case #2, there is an ambiguity near the point of offset
1404  * wraparound. If we see next multixact's offset is one, is that our
1405  * multixact's actual endpoint, or did it end at zero with a subsequent
1406  * increment? We handle this using the knowledge that if the zero'th
1407  * member slot wasn't filled, it'll contain zero, and zero isn't a valid
1408  * transaction ID so it can't be a multixact member. Therefore, if we
1409  * read a zero from the members array, just ignore it.
1410  *
1411  * This is all pretty messy, but the mess occurs only in infrequent corner
1412  * cases, so it seems better than holding the MultiXactGenLock for a long
1413  * time on every multixact creation.
1414  */
1415 retry:
1416  pageno = MultiXactIdToOffsetPage(multi);
1417  entryno = MultiXactIdToOffsetEntry(multi);
1418 
1419  /* Acquire the bank lock for the page we need. */
1420  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
1421  LWLockAcquire(lock, LW_EXCLUSIVE);
1422 
1423  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
1424  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1425  offptr += entryno;
1426  offset = *offptr;
1427 
1428  Assert(offset != 0);
1429 
1430  /*
1431  * Use the same increment rule as GetNewMultiXactId(), that is, don't
1432  * handle wraparound explicitly until needed.
1433  */
1434  tmpMXact = multi + 1;
1435 
1436  if (nextMXact == tmpMXact)
1437  {
1438  /* Corner case 1: there is no next multixact */
1439  length = nextOffset - offset;
1440  }
1441  else
1442  {
1443  MultiXactOffset nextMXOffset;
1444 
1445  /* handle wraparound if needed */
1446  if (tmpMXact < FirstMultiXactId)
1447  tmpMXact = FirstMultiXactId;
1448 
1449  prev_pageno = pageno;
1450 
1451  pageno = MultiXactIdToOffsetPage(tmpMXact);
1452  entryno = MultiXactIdToOffsetEntry(tmpMXact);
1453 
1454  if (pageno != prev_pageno)
1455  {
1456  LWLock *newlock;
1457 
1458  /*
1459  * Since we're going to access a different SLRU page, if this page
1460  * falls under a different bank, release the old bank's lock and
1461  * acquire the lock of the new bank.
1462  */
1463  newlock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
1464  if (newlock != lock)
1465  {
1466  LWLockRelease(lock);
1467  LWLockAcquire(newlock, LW_EXCLUSIVE);
1468  lock = newlock;
1469  }
1470  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
1471  }
1472 
1473  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1474  offptr += entryno;
1475  nextMXOffset = *offptr;
1476 
1477  if (nextMXOffset == 0)
1478  {
1479  /* Corner case 2: next multixact is still being filled in */
1480  LWLockRelease(lock);
1482 
1484  WAIT_EVENT_MULTIXACT_CREATION);
1485  slept = true;
1486  goto retry;
1487  }
1488 
1489  length = nextMXOffset - offset;
1490  }
1491 
1492  LWLockRelease(lock);
1493  lock = NULL;
1494 
1495  /*
1496  * If we slept above, clean up state; it's no longer needed.
1497  */
1498  if (slept)
1500 
1501  ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
1502 
1503  truelength = 0;
1504  prev_pageno = -1;
1505  for (int i = 0; i < length; i++, offset++)
1506  {
1507  TransactionId *xactptr;
1508  uint32 *flagsptr;
1509  int flagsoff;
1510  int bshift;
1511  int memberoff;
1512 
1513  pageno = MXOffsetToMemberPage(offset);
1514  memberoff = MXOffsetToMemberOffset(offset);
1515 
1516  if (pageno != prev_pageno)
1517  {
1518  LWLock *newlock;
1519 
1520  /*
1521  * Since we're going to access a different SLRU page, if this page
1522  * falls under a different bank, release the old bank's lock and
1523  * acquire the lock of the new bank.
1524  */
1525  newlock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
1526  if (newlock != lock)
1527  {
1528  if (lock)
1529  LWLockRelease(lock);
1530  LWLockAcquire(newlock, LW_EXCLUSIVE);
1531  lock = newlock;
1532  }
1533 
1534  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
1535  prev_pageno = pageno;
1536  }
1537 
1538  xactptr = (TransactionId *)
1539  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1540 
1541  if (!TransactionIdIsValid(*xactptr))
1542  {
1543  /* Corner case 3: we must be looking at unused slot zero */
1544  Assert(offset == 0);
1545  continue;
1546  }
1547 
1548  flagsoff = MXOffsetToFlagsOffset(offset);
1549  bshift = MXOffsetToFlagsBitShift(offset);
1550  flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1551 
1552  ptr[truelength].xid = *xactptr;
1553  ptr[truelength].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
1554  truelength++;
1555  }
1556 
1557  LWLockRelease(lock);
1558 
1559  /* A multixid with zero members should not happen */
1560  Assert(truelength > 0);
1561 
1562  /*
1563  * Copy the result into the local cache.
1564  */
1565  mXactCachePut(multi, truelength, ptr);
1566 
1567  debug_elog3(DEBUG2, "GetMembers: no cache for %s",
1568  mxid_to_string(multi, truelength, ptr));
1569  *members = ptr;
1570  return truelength;
1571 }
unsigned int uint32
Definition: c.h:506
uint32 MultiXactOffset
Definition: c.h:664
uint32 TransactionId
Definition: c.h:652
bool ConditionVariableCancelSleep(void)
void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#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:115
void * palloc(Size size)
Definition: mcxt.c:1317
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
Definition: multixact.c:1654
static int64 MXOffsetToMemberPage(MultiXactOffset offset)
Definition: multixact.c:172
#define MXACT_MEMBER_XACT_BITMASK
Definition: multixact.c:144
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3309
static void MultiXactIdSetOldestVisible(void)
Definition: multixact.c:729
static int MultiXactIdToOffsetEntry(MultiXactId multi)
Definition: multixact.c:118
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1701
static int MXOffsetToMemberOffset(MultiXactOffset offset)
Definition: multixact.c:205
static int64 MultiXactIdToOffsetPage(MultiXactId multi)
Definition: multixact.c:112
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1769
#define debug_elog3(a, b, c)
Definition: multixact.c:381
static int MXOffsetToFlagsOffset(MultiXactOffset offset)
Definition: multixact.c:185
static MultiXactStateData * MultiXactState
Definition: multixact.c:339
static int MXOffsetToFlagsBitShift(MultiXactOffset offset)
Definition: multixact.c:195
#define debug_elog2(a, b)
Definition: multixact.c:380
#define FirstMultiXactId
Definition: multixact.h:25
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:502
TransactionId xid
Definition: multixact.h:58
MultiXactStatus status
Definition: multixact.h:59
MultiXactOffset nextOffset
Definition: multixact.c:247
MultiXactId nextMXact
Definition: multixact.c:244
MultiXactId oldestMultiXactId
Definition: multixact.c:257
ConditionVariable nextoff_cv
Definition: multixact.c:281
#define TransactionIdIsValid(xid)
Definition: transam.h:41

References Assert, CHECK_FOR_INTERRUPTS, ConditionVariableCancelSleep(), ConditionVariableSleep(), 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::nextoff_cv, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactId, OldestVisibleMXactId, palloc(), 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 2652 of file multixact.c.

2653 {
2654  MultiXactId oldestMXact;
2655  MultiXactId nextMXact;
2656  int i;
2657 
2658  /*
2659  * This is the oldest valid value among all the OldestMemberMXactId[] and
2660  * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2661  */
2662  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2663 
2664  /*
2665  * We have to beware of the possibility that nextMXact is in the
2666  * wrapped-around state. We don't fix the counter itself here, but we
2667  * must be sure to use a valid value in our calculation.
2668  */
2669  nextMXact = MultiXactState->nextMXact;
2670  if (nextMXact < FirstMultiXactId)
2671  nextMXact = FirstMultiXactId;
2672 
2673  oldestMXact = nextMXact;
2674  for (i = 0; i < MaxOldestSlot; i++)
2675  {
2676  MultiXactId thisoldest;
2677 
2678  thisoldest = OldestMemberMXactId[i];
2679  if (MultiXactIdIsValid(thisoldest) &&
2680  MultiXactIdPrecedes(thisoldest, oldestMXact))
2681  oldestMXact = thisoldest;
2682  thisoldest = OldestVisibleMXactId[i];
2683  if (MultiXactIdIsValid(thisoldest) &&
2684  MultiXactIdPrecedes(thisoldest, oldestMXact))
2685  oldestMXact = thisoldest;
2686  }
2687 
2688  LWLockRelease(MultiXactGenLock);
2689 
2690  return oldestMXact;
2691 }
#define MaxOldestSlot
Definition: multixact.c:336

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:504
#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 3386 of file multixact.c.

3387 {
3388  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3389 
3390  /* Backup blocks are not used in multixact records */
3391  Assert(!XLogRecHasAnyBlockRefs(record));
3392 
3393  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3394  {
3395  int64 pageno;
3396  int slotno;
3397  LWLock *lock;
3398 
3399  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3400 
3401  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
3402  LWLockAcquire(lock, LW_EXCLUSIVE);
3403 
3404  slotno = ZeroMultiXactOffsetPage(pageno, false);
3406  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3407 
3408  LWLockRelease(lock);
3409  }
3410  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3411  {
3412  int64 pageno;
3413  int slotno;
3414  LWLock *lock;
3415 
3416  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3417 
3418  lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
3419  LWLockAcquire(lock, LW_EXCLUSIVE);
3420 
3421  slotno = ZeroMultiXactMemberPage(pageno, false);
3423  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3424 
3425  LWLockRelease(lock);
3426  }
3427  else if (info == XLOG_MULTIXACT_CREATE_ID)
3428  {
3429  xl_multixact_create *xlrec =
3430  (xl_multixact_create *) XLogRecGetData(record);
3431  TransactionId max_xid;
3432  int i;
3433 
3434  /* Store the data back into the SLRU files */
3435  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3436  xlrec->members);
3437 
3438  /* Make sure nextMXact/nextOffset are beyond what this record has */
3439  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3440  xlrec->moff + xlrec->nmembers);
3441 
3442  /*
3443  * Make sure nextXid is beyond any XID mentioned in the record. This
3444  * should be unnecessary, since any XID found here ought to have other
3445  * evidence in the XLOG, but let's be safe.
3446  */
3447  max_xid = XLogRecGetXid(record);
3448  for (i = 0; i < xlrec->nmembers; i++)
3449  {
3450  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3451  max_xid = xlrec->members[i].xid;
3452  }
3453 
3455  }
3456  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3457  {
3458  xl_multixact_truncate xlrec;
3459  int64 pageno;
3460 
3461  memcpy(&xlrec, XLogRecGetData(record),
3463 
3464  elog(DEBUG1, "replaying multixact truncation: "
3465  "offsets [%u, %u), offsets segments [%llx, %llx), "
3466  "members [%u, %u), members segments [%llx, %llx)",
3467  xlrec.startTruncOff, xlrec.endTruncOff,
3468  (unsigned long long) MultiXactIdToOffsetSegment(xlrec.startTruncOff),
3469  (unsigned long long) MultiXactIdToOffsetSegment(xlrec.endTruncOff),
3470  xlrec.startTruncMemb, xlrec.endTruncMemb,
3471  (unsigned long long) MXOffsetToMemberSegment(xlrec.startTruncMemb),
3472  (unsigned long long) MXOffsetToMemberSegment(xlrec.endTruncMemb));
3473 
3474  /* should not be required, but more than cheap enough */
3475  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3476 
3477  /*
3478  * Advance the horizon values, so they're current at the end of
3479  * recovery.
3480  */
3481  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3482 
3484 
3485  /*
3486  * During XLOG replay, latest_page_number isn't necessarily set up
3487  * yet; insert a suitable value to bypass the sanity test in
3488  * SimpleLruTruncate.
3489  */
3490  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3491  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3492  pageno);
3494 
3495  LWLockRelease(MultiXactTruncationLock);
3496  }
3497  else
3498  elog(PANIC, "multixact_redo: unknown op code %u", info);
3499 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:478
#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:3069
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:3040
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2354
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:910
static int MXOffsetToMemberSegment(MultiXactOffset offset)
Definition: multixact.c:178
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2503
static int MultiXactIdToOffsetSegment(MultiXactId multi)
Definition: multixact.c:124
#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 1927 of file multixact.c.

1929 {
1930  multixact_twophase_postcommit(xid, info, recdata, len);
1931 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1912
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 1912 of file multixact.c.

1914 {
1915  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, true);
1916 
1917  Assert(len == sizeof(MultiXactId));
1918 
1919  OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1920 }
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 1891 of file multixact.c.

1893 {
1894  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1895  MultiXactId oldestMember;
1896 
1897  /*
1898  * Get the oldest member XID from the state file record, and set it in the
1899  * OldestMemberMXactId slot reserved for this prepared transaction.
1900  */
1901  Assert(len == sizeof(MultiXactId));
1902  oldestMember = *((MultiXactId *) recdata);
1903 
1904  OldestMemberMXactId[dummyProcNumber] = oldestMember;
1905 }

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2503 of file multixact.c.

2505 {
2506  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2508  {
2509  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2510  MultiXactState->nextMXact = minMulti;
2511  }
2512  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2513  {
2514  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2515  minMultiOffset);
2516  MultiXactState->nextOffset = minMultiOffset;
2517  }
2518  LWLockRelease(MultiXactGenLock);
2519 }
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3335

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

2529 {
2530  Assert(InRecovery);
2531 
2533  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2534 }
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 2274 of file multixact.c.

2279 {
2280  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2281  *nextMulti = MultiXactState->nextMXact;
2282  *nextMultiOffset = MultiXactState->nextOffset;
2283  *oldestMulti = MultiXactState->oldestMultiXactId;
2284  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2285  LWLockRelease(MultiXactGenLock);
2286 
2288  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2289  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2290 }
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:384

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

435 {
436  MultiXactId newMulti;
437  MultiXactMember members[2];
438 
441 
442  Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));
443 
444  /* MultiXactIdSetOldestMember() must have been called already. */
446 
447  /*
448  * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
449  * are still running. In typical usage, xid2 will be our own XID and the
450  * caller just did a check on xid1, so it'd be wasted effort.
451  */
452 
453  members[0].xid = xid1;
454  members[0].status = status1;
455  members[1].xid = xid2;
456  members[1].status = status2;
457 
458  newMulti = MultiXactIdCreateFromMembers(2, members);
459 
460  debug_elog3(DEBUG2, "Create: %s",
461  mxid_to_string(newMulti, 2, members));
462 
463  return newMulti;
464 }
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:814
#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 814 of file multixact.c.

815 {
816  MultiXactId multi;
817  MultiXactOffset offset;
818  xl_multixact_create xlrec;
819 
820  debug_elog3(DEBUG2, "Create: %s",
821  mxid_to_string(InvalidMultiXactId, nmembers, members));
822 
823  /*
824  * See if the same set of members already exists in our cache; if so, just
825  * re-use that MultiXactId. (Note: it might seem that looking in our
826  * cache is insufficient, and we ought to search disk to see if a
827  * duplicate definition already exists. But since we only ever create
828  * MultiXacts containing our own XID, in most cases any such MultiXacts
829  * were in fact created by us, and so will be in our cache. There are
830  * corner cases where someone else added us to a MultiXact without our
831  * knowledge, but it's not worth checking for.)
832  */
833  multi = mXactCacheGetBySet(nmembers, members);
834  if (MultiXactIdIsValid(multi))
835  {
836  debug_elog2(DEBUG2, "Create: in cache!");
837  return multi;
838  }
839 
840  /* Verify that there is a single update Xid among the given members. */
841  {
842  int i;
843  bool has_update = false;
844 
845  for (i = 0; i < nmembers; i++)
846  {
847  if (ISUPDATE_from_mxstatus(members[i].status))
848  {
849  if (has_update)
850  elog(ERROR, "new multixact has more than one updating member: %s",
851  mxid_to_string(InvalidMultiXactId, nmembers, members));
852  has_update = true;
853  }
854  }
855  }
856 
857  /*
858  * Assign the MXID and offsets range to use, and make sure there is space
859  * in the OFFSETs and MEMBERs files. NB: this routine does
860  * START_CRIT_SECTION().
861  *
862  * Note: unlike MultiXactIdCreate and MultiXactIdExpand, we do not check
863  * that we've called MultiXactIdSetOldestMember here. This is because
864  * this routine is used in some places to create new MultiXactIds of which
865  * the current backend is not a member, notably during freezing of multis
866  * in vacuum. During vacuum, in particular, it would be unacceptable to
867  * keep OldestMulti set, in case it runs for long.
868  */
869  multi = GetNewMultiXactId(nmembers, &offset);
870 
871  /* Make an XLOG entry describing the new MXID. */
872  xlrec.mid = multi;
873  xlrec.moff = offset;
874  xlrec.nmembers = nmembers;
875 
876  /*
877  * XXX Note: there's a lot of padding space in MultiXactMember. We could
878  * find a more compact representation of this Xlog record -- perhaps all
879  * the status flags in one XLogRecData, then all the xids in another one?
880  * Not clear that it's worth the trouble though.
881  */
882  XLogBeginInsert();
883  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactCreate);
884  XLogRegisterData((char *) members, nmembers * sizeof(MultiXactMember));
885 
886  (void) XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_CREATE_ID);
887 
888  /* Now enter the information into the OFFSETs and MEMBERs logs */
889  RecordNewMultiXact(multi, offset, nmembers, members);
890 
891  /* Done with critical section */
893 
894  /* Store the new MultiXactId in the local cache, too */
895  mXactCachePut(multi, nmembers, members);
896 
897  debug_elog2(DEBUG2, "Create: all done");
898 
899  return multi;
900 }
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
Definition: multixact.c:1026
static MultiXactId mXactCacheGetBySet(int nmembers, MultiXactMember *members)
Definition: multixact.c:1611
#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 486 of file multixact.c.

487 {
488  MultiXactId newMulti;
489  MultiXactMember *members;
490  MultiXactMember *newMembers;
491  int nmembers;
492  int i;
493  int j;
494 
495  Assert(MultiXactIdIsValid(multi));
497 
498  /* MultiXactIdSetOldestMember() must have been called already. */
500 
501  debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s",
502  multi, xid, mxstatus_to_string(status));
503 
504  /*
505  * Note: we don't allow for old multis here. The reason is that the only
506  * caller of this function does a check that the multixact is no longer
507  * running.
508  */
509  nmembers = GetMultiXactIdMembers(multi, &members, false, false);
510 
511  if (nmembers < 0)
512  {
513  MultiXactMember member;
514 
515  /*
516  * The MultiXactId is obsolete. This can only happen if all the
517  * MultiXactId members stop running between the caller checking and
518  * passing it to us. It would be better to return that fact to the
519  * caller, but it would complicate the API and it's unlikely to happen
520  * too often, so just deal with it by creating a singleton MultiXact.
521  */
522  member.xid = xid;
523  member.status = status;
524  newMulti = MultiXactIdCreateFromMembers(1, &member);
525 
526  debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
527  multi, newMulti);
528  return newMulti;
529  }
530 
531  /*
532  * If the TransactionId is already a member of the MultiXactId with the
533  * same status, just return the existing MultiXactId.
534  */
535  for (i = 0; i < nmembers; i++)
536  {
537  if (TransactionIdEquals(members[i].xid, xid) &&
538  (members[i].status == status))
539  {
540  debug_elog4(DEBUG2, "Expand: %u is already a member of %u",
541  xid, multi);
542  pfree(members);
543  return multi;
544  }
545  }
546 
547  /*
548  * Determine which of the members of the MultiXactId are still of
549  * interest. This is any running transaction, and also any transaction
550  * that grabbed something stronger than just a lock and was committed. (An
551  * update that aborted is of no interest here; and having more than one
552  * update Xid in a multixact would cause errors elsewhere.)
553  *
554  * Removing dead members is not just an optimization: freezing of tuples
555  * whose Xmax are multis depends on this behavior.
556  *
557  * Note we have the same race condition here as above: j could be 0 at the
558  * end of the loop.
559  */
560  newMembers = (MultiXactMember *)
561  palloc(sizeof(MultiXactMember) * (nmembers + 1));
562 
563  for (i = 0, j = 0; i < nmembers; i++)
564  {
565  if (TransactionIdIsInProgress(members[i].xid) ||
566  (ISUPDATE_from_mxstatus(members[i].status) &&
567  TransactionIdDidCommit(members[i].xid)))
568  {
569  newMembers[j].xid = members[i].xid;
570  newMembers[j++].status = members[i].status;
571  }
572  }
573 
574  newMembers[j].xid = xid;
575  newMembers[j++].status = status;
576  newMulti = MultiXactIdCreateFromMembers(j, newMembers);
577 
578  pfree(members);
579  pfree(newMembers);
580 
581  debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);
582 
583  return newMulti;
584 }
int j
Definition: isn.c:74
void pfree(void *pointer)
Definition: mcxt.c:1521
#define debug_elog5(a, b, c, d, e)
Definition: multixact.c:383
#define debug_elog4(a, b, c, d)
Definition: multixact.c:382
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1746
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
Definition: multixact.c:1293
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1402
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 598 of file multixact.c.

599 {
600  MultiXactMember *members;
601  int nmembers;
602  int i;
603 
604  debug_elog3(DEBUG2, "IsRunning %u?", multi);
605 
606  /*
607  * "false" here means we assume our callers have checked that the given
608  * multi cannot possibly come from a pg_upgraded database.
609  */
610  nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
611 
612  if (nmembers <= 0)
613  {
614  debug_elog2(DEBUG2, "IsRunning: no members");
615  return false;
616  }
617 
618  /*
619  * Checking for myself is cheap compared to looking in shared memory;
620  * return true if any live subtransaction of the current top-level
621  * transaction is a member.
622  *
623  * This is not needed for correctness, it's just a fast path.
624  */
625  for (i = 0; i < nmembers; i++)
626  {
627  if (TransactionIdIsCurrentTransactionId(members[i].xid))
628  {
629  debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i);
630  pfree(members);
631  return true;
632  }
633  }
634 
635  /*
636  * This could be made faster by having another entry point in procarray.c,
637  * walking the PGPROC array only once for all the members. But in most
638  * cases nmembers should be small enough that it doesn't much matter.
639  */
640  for (i = 0; i < nmembers; i++)
641  {
642  if (TransactionIdIsInProgress(members[i].xid))
643  {
644  debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running",
645  i, members[i].xid);
646  pfree(members);
647  return true;
648  }
649  }
650 
651  pfree(members);
652 
653  debug_elog3(DEBUG2, "IsRunning: %u is not running", multi);
654 
655  return false;
656 }
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:939

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

3324 {
3325  int32 diff = (int32) (multi1 - multi2);
3326 
3327  return (diff <= 0);
3328 }

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

673 {
675  {
676  MultiXactId nextMXact;
677 
678  /*
679  * You might think we don't need to acquire a lock here, since
680  * fetching and storing of TransactionIds is probably atomic, but in
681  * fact we do: suppose we pick up nextMXact and then lose the CPU for
682  * a long time. Someone else could advance nextMXact, and then
683  * another someone else could compute an OldestVisibleMXactId that
684  * would be after the value we are going to store when we get control
685  * back. Which would be wrong.
686  *
687  * Note that a shared lock is sufficient, because it's enough to stop
688  * someone from advancing nextMXact; and nobody else could be trying
689  * to write to our OldestMember entry, only reading (and we assume
690  * storing it is atomic.)
691  */
692  LWLockAcquire(MultiXactGenLock, LW_SHARED);
693 
694  /*
695  * We have to beware of the possibility that nextMXact is in the
696  * wrapped-around state. We don't fix the counter itself here, but we
697  * must be sure to store a valid value in our array entry.
698  */
699  nextMXact = MultiXactState->nextMXact;
700  if (nextMXact < FirstMultiXactId)
701  nextMXact = FirstMultiXactId;
702 
703  OldestMemberMXactId[MyProcNumber] = nextMXact;
704 
705  LWLockRelease(MultiXactGenLock);
706 
707  debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
708  MyProcNumber, nextMXact);
709  }
710 }

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

2971 {
2972  MultiXactOffset members;
2973  uint32 multixacts;
2974  uint32 victim_multixacts;
2975  double fraction;
2976  int result;
2977 
2978  /* If we can't determine member space utilization, assume the worst. */
2979  if (!ReadMultiXactCounts(&multixacts, &members))
2980  return 0;
2981 
2982  /* If member space utilization is low, no special action is required. */
2983  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2985 
2986  /*
2987  * Compute a target for relminmxid advancement. The number of multixacts
2988  * we try to eliminate from the system is based on how far we are past
2989  * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2990  */
2991  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2993  victim_multixacts = multixacts * fraction;
2994 
2995  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2996  if (victim_multixacts > multixacts)
2997  return 0;
2998  result = multixacts - victim_multixacts;
2999 
3000  /*
3001  * Clamp to autovacuum_multixact_freeze_max_age, so that we never make
3002  * autovacuum less aggressive than it would otherwise be.
3003  */
3004  return Min(result, autovacuum_multixact_freeze_max_age);
3005 }
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:128
#define Min(x, y)
Definition: c.h:1004
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:215
static bool ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
Definition: multixact.c:2918
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:216

References autovacuum_multixact_freeze_max_age, Min, 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 3576 of file multixact.c.

3577 {
3578  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3579 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1828

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3567 of file multixact.c.

3568 {
3569  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3570 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2320 of file multixact.c.

2322 {
2323  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2324  nextMulti, nextMultiOffset);
2325  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2326  MultiXactState->nextMXact = nextMulti;
2327  MultiXactState->nextOffset = nextMultiOffset;
2328  LWLockRelease(MultiXactGenLock);
2329 
2330  /*
2331  * During a binary upgrade, make sure that the offsets SLRU is large
2332  * enough to contain the next value that would be created.
2333  *
2334  * We need to do this pretty early during the first startup in binary
2335  * upgrade mode: before StartupMultiXact() in fact, because this routine
2336  * is called even before that by StartupXLOG(). And we can't do it
2337  * earlier than at this point, because during that first call of this
2338  * routine we determine the MultiXactState->nextMXact value that
2339  * MaybeExtendOffsetSlru needs.
2340  */
2341  if (IsBinaryUpgrade)
2343 }
bool IsBinaryUpgrade
Definition: globals.c:119
static void MaybeExtendOffsetSlru(void)
Definition: multixact.c:2110

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

1957 {
1958  bool found;
1959 
1960  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1961 
1964 
1966  "multixact_offset", multixact_offset_buffers, 0,
1967  "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1970  false);
1973  "multixact_member", multixact_member_buffers, 0,
1974  "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1977  false);
1978  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1979 
1980  /* Initialize our shared state struct */
1981  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1983  &found);
1984  if (!IsUnderPostmaster)
1985  {
1986  Assert(!found);
1987 
1988  /* Make sure we zero out the per-backend state */
1991  }
1992  else
1993  Assert(found);
1994 
1995  /*
1996  * Set up array pointers.
1997  */
2000 }
#define MemSet(start, val, len)
Definition: c.h:1020
void ConditionVariableInit(ConditionVariable *cv)
int multixact_offset_buffers
Definition: globals.c:165
bool IsUnderPostmaster
Definition: globals.c:118
int multixact_member_buffers
Definition: globals.c:164
@ LWTRANCHE_MULTIXACTOFFSET_SLRU
Definition: lwlock.h:212
@ LWTRANCHE_MULTIXACTMEMBER_SLRU
Definition: lwlock.h:211
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:183
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:182
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3289
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3269
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:252
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:202
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:330
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40

References Assert, ConditionVariableInit(), 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, MultiXactStateData::nextoff_cv, 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 1939 of file multixact.c.

1940 {
1941  Size size;
1942 
1943  /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1944 #define SHARED_MULTIXACT_STATE_SIZE \
1945  add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1946  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1947 
1951 
1952  return size;
1953 }
size_t Size
Definition: c.h:605
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:199

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

1770 {
1771  static char *str = NULL;
1773  int i;
1774 
1775  if (str != NULL)
1776  pfree(str);
1777 
1778  initStringInfo(&buf);
1779 
1780  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1781  mxstatus_to_string(members[0].status));
1782 
1783  for (i = 1; i < nmembers; i++)
1784  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1785  mxstatus_to_string(members[i].status));
1786 
1787  appendStringInfoChar(&buf, ']');
1789  pfree(buf.data);
1790  return str;
1791 }
const char * str
MemoryContext TopMemoryContext
Definition: mcxt.c:149
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
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(), str, and TopMemoryContext.

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

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1842 of file multixact.c.

1843 {
1844  MultiXactId myOldestMember;
1845 
1846  /*
1847  * Transfer our OldestMemberMXactId value to the slot reserved for the
1848  * prepared transaction.
1849  */
1850  myOldestMember = OldestMemberMXactId[MyProcNumber];
1851  if (MultiXactIdIsValid(myOldestMember))
1852  {
1853  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1854 
1855  /*
1856  * Even though storing MultiXactId is atomic, acquire lock to make
1857  * sure others see both changes, not just the reset of the slot of the
1858  * current backend. Using a volatile pointer might suffice, but this
1859  * isn't a hot spot.
1860  */
1861  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1862 
1863  OldestMemberMXactId[dummyProcNumber] = myOldestMember;
1865 
1866  LWLockRelease(MultiXactGenLock);
1867  }
1868 
1869  /*
1870  * We don't need to transfer OldestVisibleMXactId value, because the
1871  * transaction is not going to be looking at any more multixacts once it's
1872  * prepared.
1873  *
1874  * We assume that storing a MultiXactId is atomic and so we need not take
1875  * MultiXactGenLock to do this.
1876  */
1878 
1879  /*
1880  * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1881  */
1882  MXactContext = NULL;
1884 }

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

791 {
792  LWLockAcquire(MultiXactGenLock, LW_SHARED);
795  LWLockRelease(MultiXactGenLock);
796 
797  if (*oldest < FirstMultiXactId)
798  *oldest = FirstMultiXactId;
799  if (*next < FirstMultiXactId)
801 }
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 770 of file multixact.c.

771 {
772  MultiXactId mxid;
773 
774  /* XXX we could presumably do this without a lock. */
775  LWLockAcquire(MultiXactGenLock, LW_SHARED);
776  mxid = MultiXactState->nextMXact;
777  LWLockRelease(MultiXactGenLock);
778 
779  if (mxid < FirstMultiXactId)
780  mxid = FirstMultiXactId;
781 
782  return mxid;
783 }

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

2356 {
2357  MultiXactId multiVacLimit;
2358  MultiXactId multiWarnLimit;
2359  MultiXactId multiStopLimit;
2360  MultiXactId multiWrapLimit;
2361  MultiXactId curMulti;
2362  bool needs_offset_vacuum;
2363 
2364  Assert(MultiXactIdIsValid(oldest_datminmxid));
2365 
2366  /*
2367  * We pretend that a wrap will happen halfway through the multixact ID
2368  * space, but that's not really true, because multixacts wrap differently
2369  * from transaction IDs. Note that, separately from any concern about
2370  * multixact IDs wrapping, we must ensure that multixact members do not
2371  * wrap. Limits for that are set in SetOffsetVacuumLimit, not here.
2372  */
2373  multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
2374  if (multiWrapLimit < FirstMultiXactId)
2375  multiWrapLimit += FirstMultiXactId;
2376 
2377  /*
2378  * We'll refuse to continue assigning MultiXactIds once we get within 3M
2379  * multi of data loss. See SetTransactionIdLimit.
2380  */
2381  multiStopLimit = multiWrapLimit - 3000000;
2382  if (multiStopLimit < FirstMultiXactId)
2383  multiStopLimit -= FirstMultiXactId;
2384 
2385  /*
2386  * We'll start complaining loudly when we get within 40M multis of data
2387  * loss. This is kind of arbitrary, but if you let your gas gauge get
2388  * down to 2% of full, would you be looking for the next gas station? We
2389  * need to be fairly liberal about this number because there are lots of
2390  * scenarios where most transactions are done by automatic clients that
2391  * won't pay attention to warnings. (No, we're not gonna make this
2392  * configurable. If you know enough to configure it, you know enough to
2393  * not get in this kind of trouble in the first place.)
2394  */
2395  multiWarnLimit = multiWrapLimit - 40000000;
2396  if (multiWarnLimit < FirstMultiXactId)
2397  multiWarnLimit -= FirstMultiXactId;
2398 
2399  /*
2400  * We'll start trying to force autovacuums when oldest_datminmxid gets to
2401  * be more than autovacuum_multixact_freeze_max_age mxids old.
2402  *
2403  * Note: autovacuum_multixact_freeze_max_age is a PGC_POSTMASTER parameter
2404  * so that we don't have to worry about dealing with on-the-fly changes in
2405  * its value. See SetTransactionIdLimit.
2406  */
2407  multiVacLimit = oldest_datminmxid + autovacuum_multixact_freeze_max_age;
2408  if (multiVacLimit < FirstMultiXactId)
2409  multiVacLimit += FirstMultiXactId;
2410 
2411  /* Grab lock for just long enough to set the new limit values */
2412  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2413  MultiXactState->oldestMultiXactId = oldest_datminmxid;
2414  MultiXactState->oldestMultiXactDB = oldest_datoid;
2415  MultiXactState->multiVacLimit = multiVacLimit;
2416  MultiXactState->multiWarnLimit = multiWarnLimit;
2417  MultiXactState->multiStopLimit = multiStopLimit;
2418  MultiXactState->multiWrapLimit = multiWrapLimit;
2419  curMulti = MultiXactState->nextMXact;
2420  LWLockRelease(MultiXactGenLock);
2421 
2422  /* Log the info */
2423  ereport(DEBUG1,
2424  (errmsg_internal("MultiXactId wrap limit is %u, limited by database with OID %u",
2425  multiWrapLimit, oldest_datoid)));
2426 
2427  /*
2428  * Computing the actual limits is only possible once the data directory is
2429  * in a consistent state. There's no need to compute the limits while
2430  * still replaying WAL - no decisions about new multis are made even
2431  * though multixact creations might be replayed. So we'll only do further
2432  * checks after TrimMultiXact() has been called.
2433  */
2435  return;
2436 
2437  Assert(!InRecovery);
2438 
2439  /* Set limits for offset vacuum. */
2440  needs_offset_vacuum = SetOffsetVacuumLimit(is_startup);
2441 
2442  /*
2443  * If past the autovacuum force point, immediately signal an autovac
2444  * request. The reason for this is that autovac only processes one
2445  * database per invocation. Once it's finished cleaning up the oldest
2446  * database, it'll call here, and we'll signal the postmaster to start
2447  * another iteration immediately if there are still any old databases.
2448  */
2449  if ((MultiXactIdPrecedes(multiVacLimit, curMulti) ||
2450  needs_offset_vacuum) && IsUnderPostmaster)
2452 
2453  /* Give an immediate warning if past the wrap warn point */
2454  if (MultiXactIdPrecedes(multiWarnLimit, curMulti))
2455  {
2456  char *oldest_datname;
2457 
2458  /*
2459  * We can be called when not inside a transaction, for example during
2460  * StartupXLOG(). In such a case we cannot do database access, so we
2461  * must just report the oldest DB's OID.
2462  *
2463  * Note: it's also possible that get_database_name fails and returns
2464  * NULL, for example because the database just got dropped. We'll
2465  * still warn, even though the warning might now be unnecessary.
2466  */
2467  if (IsTransactionState())
2468  oldest_datname = get_database_name(oldest_datoid);
2469  else
2470  oldest_datname = NULL;
2471 
2472  if (oldest_datname)
2473  ereport(WARNING,
2474  (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
2475  "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
2476  multiWrapLimit - curMulti,
2477  oldest_datname,
2478  multiWrapLimit - curMulti),
2479  errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2480  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2481  else
2482  ereport(WARNING,
2483  (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
2484  "database with OID %u must be vacuumed before %u more MultiXactIds are used",
2485  multiWrapLimit - curMulti,
2486  oldest_datoid,
2487  multiWrapLimit - curMulti),
2488  errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2489  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2490  }
2491 }
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3166
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1180
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errhint(const char *fmt,...)
Definition: elog.c:1317
#define WARNING
Definition: elog.h:36
static bool SetOffsetVacuumLimit(bool is_startup)
Definition: multixact.c:2705
#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:272
MultiXactId multiStopLimit
Definition: multixact.c:271
MultiXactId multiWarnLimit
Definition: multixact.c:270
MultiXactId multiVacLimit
Definition: multixact.c:269
bool IsTransactionState(void)
Definition: xact.c:385

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

2146 {
2149  int64 pageno;
2150 
2151  /*
2152  * Initialize offset's idea of the latest page number.
2153  */
2154  pageno = MultiXactIdToOffsetPage(multi);
2155  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2156  pageno);
2157 
2158  /*
2159  * Initialize member's idea of the latest page number.
2160  */
2161  pageno = MXOffsetToMemberPage(offset);
2162  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2163  pageno);
2164 }

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

2171 {
2172  MultiXactId nextMXact;
2173  MultiXactOffset offset;
2174  MultiXactId oldestMXact;
2175  Oid oldestMXactDB;
2176  int64 pageno;
2177  int entryno;
2178  int flagsoff;
2179 
2180  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2181  nextMXact = MultiXactState->nextMXact;
2182  offset = MultiXactState->nextOffset;
2183  oldestMXact = MultiXactState->oldestMultiXactId;
2184  oldestMXactDB = MultiXactState->oldestMultiXactDB;
2185  LWLockRelease(MultiXactGenLock);
2186 
2187  /* Clean up offsets state */
2188 
2189  /*
2190  * (Re-)Initialize our idea of the latest page number for offsets.
2191  */
2192  pageno = MultiXactIdToOffsetPage(nextMXact);
2193  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2194  pageno);
2195 
2196  /*
2197  * Zero out the remainder of the current offsets page. See notes in
2198  * TrimCLOG() for background. Unlike CLOG, some WAL record covers every
2199  * pg_multixact SLRU mutation. Since, also unlike CLOG, we ignore the WAL
2200  * rule "write xlog before data," nextMXact successors may carry obsolete,
2201  * nonzero offset values. Zero those so case 2 of GetMultiXactIdMembers()
2202  * operates normally.
2203  */
2204  entryno = MultiXactIdToOffsetEntry(nextMXact);
2205  if (entryno != 0)
2206  {
2207  int slotno;
2208  MultiXactOffset *offptr;
2210 
2211  LWLockAcquire(lock, LW_EXCLUSIVE);
2212  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2213  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2214  offptr += entryno;
2215 
2216  MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
2217 
2218  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2219  LWLockRelease(lock);
2220  }
2221 
2222  /*
2223  * And the same for members.
2224  *
2225  * (Re-)Initialize our idea of the latest page number for members.
2226  */
2227  pageno = MXOffsetToMemberPage(offset);
2228  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2229  pageno);
2230 
2231  /*
2232  * Zero out the remainder of the current members page. See notes in
2233  * TrimCLOG() for motivation.
2234  */
2235  flagsoff = MXOffsetToFlagsOffset(offset);
2236  if (flagsoff != 0)
2237  {
2238  int slotno;
2239  TransactionId *xidptr;
2240  int memberoff;
2242 
2243  LWLockAcquire(lock, LW_EXCLUSIVE);
2244  memberoff = MXOffsetToMemberOffset(offset);
2245  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2246  xidptr = (TransactionId *)
2247  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2248 
2249  MemSet(xidptr, 0, BLCKSZ - memberoff);
2250 
2251  /*
2252  * Note: we don't need to zero out the flag bits in the remaining
2253  * members of the current group, because they are always reset before
2254  * writing.
2255  */
2256 
2257  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2258  LWLockRelease(lock);
2259  }
2260 
2261  /* signal that we're officially up */
2262  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2264  LWLockRelease(MultiXactGenLock);
2265 
2266  /* Now compute how far away the next members wraparound is. */
2267  SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2268 }
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 3094 of file multixact.c.

3095 {
3096  MultiXactId oldestMulti;
3097  MultiXactId nextMulti;
3098  MultiXactOffset newOldestOffset;
3099  MultiXactOffset oldestOffset;
3100  MultiXactOffset nextOffset;
3101  mxtruncinfo trunc;
3102  MultiXactId earliest;
3103 
3106 
3107  /*
3108  * We can only allow one truncation to happen at once. Otherwise parts of
3109  * members might vanish while we're doing lookups or similar. There's no
3110  * need to have an interlock with creating new multis or such, since those
3111  * are constrained by the limits (which only grow, never shrink).
3112  */
3113  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3114 
3115  LWLockAcquire(MultiXactGenLock, LW_SHARED);
3116  nextMulti = MultiXactState->nextMXact;
3117  nextOffset = MultiXactState->nextOffset;
3118  oldestMulti = MultiXactState->oldestMultiXactId;
3119  LWLockRelease(MultiXactGenLock);
3120  Assert(MultiXactIdIsValid(oldestMulti));
3121 
3122  /*
3123  * Make sure to only attempt truncation if there's values to truncate
3124  * away. In normal processing values shouldn't go backwards, but there's
3125  * some corner cases (due to bugs) where that's possible.
3126  */
3127  if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
3128  {
3129  LWLockRelease(MultiXactTruncationLock);
3130  return;
3131  }
3132 
3133  /*
3134  * Note we can't just plow ahead with the truncation; it's possible that
3135  * there are no segments to truncate, which is a problem because we are
3136  * going to attempt to read the offsets page to determine where to
3137  * truncate the members SLRU. So we first scan the directory to determine
3138  * the earliest offsets page number that we can read without error.
3139  *
3140  * When nextMXact is less than one segment away from multiWrapLimit,
3141  * SlruScanDirCbFindEarliest can find some early segment other than the
3142  * actual earliest. (MultiXactOffsetPagePrecedes(EARLIEST, LATEST)
3143  * returns false, because not all pairs of entries have the same answer.)
3144  * That can also arise when an earlier truncation attempt failed unlink()
3145  * or returned early from this function. The only consequence is
3146  * returning early, which wastes space that we could have liberated.
3147  *
3148  * NB: It's also possible that the page that oldestMulti is on has already
3149  * been truncated away, and we crashed before updating oldestMulti.
3150  */
3151  trunc.earliestExistingPage = -1;
3154  if (earliest < FirstMultiXactId)
3155  earliest = FirstMultiXactId;
3156 
3157  /* If there's nothing to remove, we can bail out early. */
3158  if (MultiXactIdPrecedes(oldestMulti, earliest))
3159  {
3160  LWLockRelease(MultiXactTruncationLock);
3161  return;
3162  }
3163 
3164  /*
3165  * First, compute the safe truncation point for MultiXactMember. This is
3166  * the starting offset of the oldest multixact.
3167  *
3168  * Hopefully, find_multixact_start will always work here, because we've
3169  * already checked that it doesn't precede the earliest MultiXact on disk.
3170  * But if it fails, don't truncate anything, and log a message.
3171  */
3172  if (oldestMulti == nextMulti)
3173  {
3174  /* there are NO MultiXacts */
3175  oldestOffset = nextOffset;
3176  }
3177  else if (!find_multixact_start(oldestMulti, &oldestOffset))
3178  {
3179  ereport(LOG,
3180  (errmsg("oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
3181  oldestMulti, earliest)));
3182  LWLockRelease(MultiXactTruncationLock);
3183  return;
3184  }
3185 
3186  /*
3187  * Secondly compute up to where to truncate. Lookup the corresponding
3188  * member offset for newOldestMulti for that.
3189  */
3190  if (newOldestMulti == nextMulti)
3191  {
3192  /* there are NO MultiXacts */
3193  newOldestOffset = nextOffset;
3194  }
3195  else if (!find_multixact_start(newOldestMulti, &newOldestOffset))
3196  {
3197  ereport(LOG,
3198  (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
3199  newOldestMulti)));
3200  LWLockRelease(MultiXactTruncationLock);
3201  return;
3202  }
3203 
3204  elog(DEBUG1, "performing multixact truncation: "
3205  "offsets [%u, %u), offsets segments [%llx, %llx), "
3206  "members [%u, %u), members segments [%llx, %llx)",
3207  oldestMulti, newOldestMulti,
3208  (unsigned long long) MultiXactIdToOffsetSegment(oldestMulti),
3209  (unsigned long long) MultiXactIdToOffsetSegment(newOldestMulti),
3210  oldestOffset, newOldestOffset,
3211  (unsigned long long) MXOffsetToMemberSegment(oldestOffset),
3212  (unsigned long long) MXOffsetToMemberSegment(newOldestOffset));
3213 
3214  /*
3215  * Do truncation, and the WAL logging of the truncation, in a critical
3216  * section. That way offsets/members cannot get out of sync anymore, i.e.
3217  * once consistent the newOldestMulti will always exist in members, even
3218  * if we crashed in the wrong moment.
3219  */
3221 
3222  /*
3223  * Prevent checkpoints from being scheduled concurrently. This is critical
3224  * because otherwise a truncation record might not be replayed after a
3225  * crash/basebackup, even though the state of the data directory would
3226  * require it.
3227  */
3230 
3231  /* WAL log truncation */
3232  WriteMTruncateXlogRec(newOldestMultiDB,
3233  oldestMulti, newOldestMulti,
3234  oldestOffset, newOldestOffset);
3235 
3236  /*
3237  * Update in-memory limits before performing the truncation, while inside
3238  * the critical section: Have to do it before truncation, to prevent
3239  * concurrent lookups of those values. Has to be inside the critical
3240  * section as otherwise a future call to this function would error out,
3241  * while looking up the oldest member in offsets, if our caller crashes
3242  * before updating the limits.
3243  */
3244  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
3245  MultiXactState->oldestMultiXactId = newOldestMulti;
3246  MultiXactState->oldestMultiXactDB = newOldestMultiDB;
3247  LWLockRelease(MultiXactGenLock);
3248 
3249  /* First truncate members */
3250  PerformMembersTruncation(oldestOffset, newOldestOffset);
3251 
3252  /* Then offsets */
3253  PerformOffsetsTruncation(oldestMulti, newOldestMulti);
3254 
3256 
3257  END_CRIT_SECTION();
3258  LWLockRelease(MultiXactTruncationLock);
3259 }
#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:3361
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition: multixact.c:2880
static bool SlruScanDirCbFindEarliest(SlruCtl ctl, char *filename, int64 segpage, void *data)
Definition: multixact.c:3017
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3323
#define DELAY_CHKPT_START
Definition: proc.h:114
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1788
PGPROC * MyProc
Definition: proc.c:66
int delayChkptFlags
Definition: proc.h:235
int64 earliestExistingPage
Definition: multixact.c:3009
bool RecoveryInProgress(void)
Definition: xlog.c:6304

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