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

1760 {
1761  /*
1762  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1763  * which should only be valid while within a transaction.
1764  *
1765  * We assume that storing a MultiXactId is atomic and so we need not take
1766  * MultiXactGenLock to do this.
1767  */
1770 
1771  /*
1772  * Discard the local MultiXactId cache. Since MXactContext was created as
1773  * a child of TopTransactionContext, we needn't delete it explicitly.
1774  */
1775  MXactContext = NULL;
1777 }
ProcNumber MyProcNumber
Definition: globals.c:87
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:330
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:300
static dclist_head MXactCache
Definition: multixact.c:329
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:299
#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 1787 of file multixact.c.

1788 {
1789  MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
1790 
1791  if (MultiXactIdIsValid(myOldestMember))
1793  &myOldestMember, sizeof(MultiXactId));
1794 }
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 1985 of file multixact.c.

1986 {
1987  int slotno;
1988  LWLock *lock;
1989 
1991  LWLockAcquire(lock, LW_EXCLUSIVE);
1992 
1993  /* Create and zero the first page of the offsets log */
1994  slotno = ZeroMultiXactOffsetPage(0, false);
1995 
1996  /* Make sure it's written out */
1998  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1999 
2000  LWLockRelease(lock);
2001 
2003  LWLockAcquire(lock, LW_EXCLUSIVE);
2004 
2005  /* Create and zero the first page of the members log */
2006  slotno = ZeroMultiXactMemberPage(0, false);
2007 
2008  /* Make sure it's written out */
2010  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
2011 
2012  LWLockRelease(lock);
2013 }
#define Assert(condition)
Definition: c.h:858
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2041
#define MultiXactMemberCtl
Definition: multixact.c:191
#define MultiXactOffsetCtl
Definition: multixact.c:190
static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2025
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:715
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:179
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 2255 of file multixact.c.

2256 {
2257  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2258 
2259  /*
2260  * Write dirty MultiXact pages to disk. This may result in sync requests
2261  * queued for later handling by ProcessSyncRequests(), as part of the
2262  * checkpoint.
2263  */
2266 
2267  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2268 }
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 1252 of file multixact.c.

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

2612 {
2613  MultiXactId oldestMXact;
2614  MultiXactId nextMXact;
2615  int i;
2616 
2617  /*
2618  * This is the oldest valid value among all the OldestMemberMXactId[] and
2619  * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2620  */
2621  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2622 
2623  /*
2624  * We have to beware of the possibility that nextMXact is in the
2625  * wrapped-around state. We don't fix the counter itself here, but we
2626  * must be sure to use a valid value in our calculation.
2627  */
2628  nextMXact = MultiXactState->nextMXact;
2629  if (nextMXact < FirstMultiXactId)
2630  nextMXact = FirstMultiXactId;
2631 
2632  oldestMXact = nextMXact;
2633  for (i = 0; i < MaxOldestSlot; i++)
2634  {
2635  MultiXactId thisoldest;
2636 
2637  thisoldest = OldestMemberMXactId[i];
2638  if (MultiXactIdIsValid(thisoldest) &&
2639  MultiXactIdPrecedes(thisoldest, oldestMXact))
2640  oldestMXact = thisoldest;
2641  thisoldest = OldestVisibleMXactId[i];
2642  if (MultiXactIdIsValid(thisoldest) &&
2643  MultiXactIdPrecedes(thisoldest, oldestMXact))
2644  oldestMXact = thisoldest;
2645  }
2646 
2647  LWLockRelease(MultiXactGenLock);
2648 
2649  return oldestMXact;
2650 }
#define MaxOldestSlot
Definition: multixact.c:295

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

3338 {
3339  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3340 
3341  /* Backup blocks are not used in multixact records */
3342  Assert(!XLogRecHasAnyBlockRefs(record));
3343 
3344  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3345  {
3346  int64 pageno;
3347  int slotno;
3348  LWLock *lock;
3349 
3350  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3351 
3352  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
3353  LWLockAcquire(lock, LW_EXCLUSIVE);
3354 
3355  slotno = ZeroMultiXactOffsetPage(pageno, false);
3357  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3358 
3359  LWLockRelease(lock);
3360  }
3361  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3362  {
3363  int64 pageno;
3364  int slotno;
3365  LWLock *lock;
3366 
3367  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3368 
3369  lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
3370  LWLockAcquire(lock, LW_EXCLUSIVE);
3371 
3372  slotno = ZeroMultiXactMemberPage(pageno, false);
3374  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3375 
3376  LWLockRelease(lock);
3377  }
3378  else if (info == XLOG_MULTIXACT_CREATE_ID)
3379  {
3380  xl_multixact_create *xlrec =
3381  (xl_multixact_create *) XLogRecGetData(record);
3382  TransactionId max_xid;
3383  int i;
3384 
3385  /* Store the data back into the SLRU files */
3386  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3387  xlrec->members);
3388 
3389  /* Make sure nextMXact/nextOffset are beyond what this record has */
3390  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3391  xlrec->moff + xlrec->nmembers);
3392 
3393  /*
3394  * Make sure nextXid is beyond any XID mentioned in the record. This
3395  * should be unnecessary, since any XID found here ought to have other
3396  * evidence in the XLOG, but let's be safe.
3397  */
3398  max_xid = XLogRecGetXid(record);
3399  for (i = 0; i < xlrec->nmembers; i++)
3400  {
3401  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3402  max_xid = xlrec->members[i].xid;
3403  }
3404 
3406  }
3407  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3408  {
3409  xl_multixact_truncate xlrec;
3410  int64 pageno;
3411 
3412  memcpy(&xlrec, XLogRecGetData(record),
3414 
3415  elog(DEBUG1, "replaying multixact truncation: "
3416  "offsets [%u, %u), offsets segments [%x, %x), "
3417  "members [%u, %u), members segments [%x, %x)",
3418  xlrec.startTruncOff, xlrec.endTruncOff,
3421  xlrec.startTruncMemb, xlrec.endTruncMemb,
3424 
3425  /* should not be required, but more than cheap enough */
3426  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3427 
3428  /*
3429  * Advance the horizon values, so they're current at the end of
3430  * recovery.
3431  */
3432  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3433 
3435 
3436  /*
3437  * During XLOG replay, latest_page_number isn't necessarily set up
3438  * yet; insert a suitable value to bypass the sanity test in
3439  * SimpleLruTruncate.
3440  */
3441  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3442  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3443  pageno);
3445 
3446  LWLockRelease(MultiXactTruncationLock);
3447  }
3448  else
3449  elog(PANIC, "multixact_redo: unknown op code %u", info);
3450 }
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:3020
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2992
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2313
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:869
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2462
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
#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 1886 of file multixact.c.

1888 {
1889  multixact_twophase_postcommit(xid, info, recdata, len);
1890 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1871
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 1871 of file multixact.c.

1873 {
1874  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, true);
1875 
1876  Assert(len == sizeof(MultiXactId));
1877 
1878  OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1879 }
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 1850 of file multixact.c.

1852 {
1853  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1854  MultiXactId oldestMember;
1855 
1856  /*
1857  * Get the oldest member XID from the state file record, and set it in the
1858  * OldestMemberMXactId slot reserved for this prepared transaction.
1859  */
1860  Assert(len == sizeof(MultiXactId));
1861  oldestMember = *((MultiXactId *) recdata);
1862 
1863  OldestMemberMXactId[dummyProcNumber] = oldestMember;
1864 }

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2462 of file multixact.c.

2464 {
2465  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2467  {
2468  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2469  MultiXactState->nextMXact = minMulti;
2470  }
2471  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2472  {
2473  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2474  minMultiOffset);
2475  MultiXactState->nextOffset = minMultiOffset;
2476  }
2477  LWLockRelease(MultiXactGenLock);
2478 }
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3286

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

2488 {
2489  Assert(InRecovery);
2490 
2492  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2493 }
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 2233 of file multixact.c.

2238 {
2239  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2240  *nextMulti = MultiXactState->nextMXact;
2241  *nextMultiOffset = MultiXactState->nextOffset;
2242  *oldestMulti = MultiXactState->oldestMultiXactId;
2243  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2244  LWLockRelease(MultiXactGenLock);
2245 
2247  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2248  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2249 }
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:343

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

394 {
395  MultiXactId newMulti;
396  MultiXactMember members[2];
397 
400 
401  Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));
402 
403  /* MultiXactIdSetOldestMember() must have been called already. */
405 
406  /*
407  * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
408  * are still running. In typical usage, xid2 will be our own XID and the
409  * caller just did a check on xid1, so it'd be wasted effort.
410  */
411 
412  members[0].xid = xid1;
413  members[0].status = status1;
414  members[1].xid = xid2;
415  members[1].status = status2;
416 
417  newMulti = MultiXactIdCreateFromMembers(2, members);
418 
419  debug_elog3(DEBUG2, "Create: %s",
420  mxid_to_string(newMulti, 2, members));
421 
422  return newMulti;
423 }
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:773
#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 773 of file multixact.c.

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

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

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

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

3275 {
3276  int32 diff = (int32) (multi1 - multi2);
3277 
3278  return (diff <= 0);
3279 }

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

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

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

2930 {
2931  MultiXactOffset members;
2932  uint32 multixacts;
2933  uint32 victim_multixacts;
2934  double fraction;
2935 
2936  /* If we can't determine member space utilization, assume the worst. */
2937  if (!ReadMultiXactCounts(&multixacts, &members))
2938  return 0;
2939 
2940  /* If member space utilization is low, no special action is required. */
2941  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2943 
2944  /*
2945  * Compute a target for relminmxid advancement. The number of multixacts
2946  * we try to eliminate from the system is based on how far we are past
2947  * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2948  */
2949  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2951  victim_multixacts = multixacts * fraction;
2952 
2953  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2954  if (victim_multixacts > multixacts)
2955  return 0;
2956  return multixacts - victim_multixacts;
2957 }
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:127
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:177
static bool ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
Definition: multixact.c:2877
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:178

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

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

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3527 of file multixact.c.

3528 {
3529  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3530 }
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 3518 of file multixact.c.

3519 {
3520  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3521 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2279 of file multixact.c.

2281 {
2282  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2283  nextMulti, nextMultiOffset);
2284  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2285  MultiXactState->nextMXact = nextMulti;
2286  MultiXactState->nextOffset = nextMultiOffset;
2287  LWLockRelease(MultiXactGenLock);
2288 
2289  /*
2290  * During a binary upgrade, make sure that the offsets SLRU is large
2291  * enough to contain the next value that would be created.
2292  *
2293  * We need to do this pretty early during the first startup in binary
2294  * upgrade mode: before StartupMultiXact() in fact, because this routine
2295  * is called even before that by StartupXLOG(). And we can't do it
2296  * earlier than at this point, because during that first call of this
2297  * routine we determine the MultiXactState->nextMXact value that
2298  * MaybeExtendOffsetSlru needs.
2299  */
2300  if (IsBinaryUpgrade)
2302 }
bool IsBinaryUpgrade
Definition: globals.c:118
static void MaybeExtendOffsetSlru(void)
Definition: multixact.c:2069

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

1916 {
1917  bool found;
1918 
1919  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1920 
1923 
1925  "multixact_offset", multixact_offset_buffers, 0,
1926  "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1929  false);
1932  "multixact_member", multixact_member_buffers, 0,
1933  "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1936  false);
1937  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1938 
1939  /* Initialize our shared state struct */
1940  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1942  &found);
1943  if (!IsUnderPostmaster)
1944  {
1945  Assert(!found);
1946 
1947  /* Make sure we zero out the per-backend state */
1950  }
1951  else
1952  Assert(found);
1953 
1954  /*
1955  * Set up array pointers.
1956  */
1959 }
#define MemSet(start, val, len)
Definition: c.h:1020
void ConditionVariableInit(ConditionVariable *cv)
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: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:3240
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3220
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:289
@ 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 1898 of file multixact.c.

1899 {
1900  Size size;
1901 
1902  /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1903 #define SHARED_MULTIXACT_STATE_SIZE \
1904  add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1905  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1906 
1910 
1911  return size;
1912 }
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: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 1728 of file multixact.c.

1729 {
1730  static char *str = NULL;
1732  int i;
1733 
1734  if (str != NULL)
1735  pfree(str);
1736 
1737  initStringInfo(&buf);
1738 
1739  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1740  mxstatus_to_string(members[0].status));
1741 
1742  for (i = 1; i < nmembers; i++)
1743  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1744  mxstatus_to_string(members[i].status));
1745 
1746  appendStringInfoChar(&buf, ']');
1748  pfree(buf.data);
1749  return str;
1750 }
const char * str
MemoryContext TopMemoryContext
Definition: mcxt.c:149
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1682
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 1801 of file multixact.c.

1802 {
1803  MultiXactId myOldestMember;
1804 
1805  /*
1806  * Transfer our OldestMemberMXactId value to the slot reserved for the
1807  * prepared transaction.
1808  */
1809  myOldestMember = OldestMemberMXactId[MyProcNumber];
1810  if (MultiXactIdIsValid(myOldestMember))
1811  {
1812  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1813 
1814  /*
1815  * Even though storing MultiXactId is atomic, acquire lock to make
1816  * sure others see both changes, not just the reset of the slot of the
1817  * current backend. Using a volatile pointer might suffice, but this
1818  * isn't a hot spot.
1819  */
1820  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1821 
1822  OldestMemberMXactId[dummyProcNumber] = myOldestMember;
1824 
1825  LWLockRelease(MultiXactGenLock);
1826  }
1827 
1828  /*
1829  * We don't need to transfer OldestVisibleMXactId value, because the
1830  * transaction is not going to be looking at any more multixacts once it's
1831  * prepared.
1832  *
1833  * We assume that storing a MultiXactId is atomic and so we need not take
1834  * MultiXactGenLock to do this.
1835  */
1837 
1838  /*
1839  * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1840  */
1841  MXactContext = NULL;
1843 }

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

750 {
751  LWLockAcquire(MultiXactGenLock, LW_SHARED);
754  LWLockRelease(MultiXactGenLock);
755 
756  if (*oldest < FirstMultiXactId)
757  *oldest = FirstMultiXactId;
758  if (*next < FirstMultiXactId)
760 }
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 729 of file multixact.c.

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

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

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

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

2105 {
2108  int64 pageno;
2109 
2110  /*
2111  * Initialize offset's idea of the latest page number.
2112  */
2113  pageno = MultiXactIdToOffsetPage(multi);
2114  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2115  pageno);
2116 
2117  /*
2118  * Initialize member's idea of the latest page number.
2119  */
2120  pageno = MXOffsetToMemberPage(offset);
2121  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2122  pageno);
2123 }

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

2130 {
2131  MultiXactId nextMXact;
2132  MultiXactOffset offset;
2133  MultiXactId oldestMXact;
2134  Oid oldestMXactDB;
2135  int64 pageno;
2136  int entryno;
2137  int flagsoff;
2138 
2139  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2140  nextMXact = MultiXactState->nextMXact;
2141  offset = MultiXactState->nextOffset;
2142  oldestMXact = MultiXactState->oldestMultiXactId;
2143  oldestMXactDB = MultiXactState->oldestMultiXactDB;
2144  LWLockRelease(MultiXactGenLock);
2145 
2146  /* Clean up offsets state */
2147 
2148  /*
2149  * (Re-)Initialize our idea of the latest page number for offsets.
2150  */
2151  pageno = MultiXactIdToOffsetPage(nextMXact);
2152  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2153  pageno);
2154 
2155  /*
2156  * Zero out the remainder of the current offsets page. See notes in
2157  * TrimCLOG() for background. Unlike CLOG, some WAL record covers every
2158  * pg_multixact SLRU mutation. Since, also unlike CLOG, we ignore the WAL
2159  * rule "write xlog before data," nextMXact successors may carry obsolete,
2160  * nonzero offset values. Zero those so case 2 of GetMultiXactIdMembers()
2161  * operates normally.
2162  */
2163  entryno = MultiXactIdToOffsetEntry(nextMXact);
2164  if (entryno != 0)
2165  {
2166  int slotno;
2167  MultiXactOffset *offptr;
2169 
2170  LWLockAcquire(lock, LW_EXCLUSIVE);
2171  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2172  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2173  offptr += entryno;
2174 
2175  MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
2176 
2177  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2178  LWLockRelease(lock);
2179  }
2180 
2181  /*
2182  * And the same for members.
2183  *
2184  * (Re-)Initialize our idea of the latest page number for members.
2185  */
2186  pageno = MXOffsetToMemberPage(offset);
2187  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2188  pageno);
2189 
2190  /*
2191  * Zero out the remainder of the current members page. See notes in
2192  * TrimCLOG() for motivation.
2193  */
2194  flagsoff = MXOffsetToFlagsOffset(offset);
2195  if (flagsoff != 0)
2196  {
2197  int slotno;
2198  TransactionId *xidptr;
2199  int memberoff;
2201 
2202  LWLockAcquire(lock, LW_EXCLUSIVE);
2203  memberoff = MXOffsetToMemberOffset(offset);
2204  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2205  xidptr = (TransactionId *)
2206  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2207 
2208  MemSet(xidptr, 0, BLCKSZ - memberoff);
2209 
2210  /*
2211  * Note: we don't need to zero out the flag bits in the remaining
2212  * members of the current group, because they are always reset before
2213  * writing.
2214  */
2215 
2216  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2217  LWLockRelease(lock);
2218  }
2219 
2220  /* signal that we're officially up */
2221  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2223  LWLockRelease(MultiXactGenLock);
2224 
2225  /* Now compute how far away the next members wraparound is. */
2226  SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2227 }
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 3045 of file multixact.c.

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

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