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

Go to the source code of this file.

Data Structures

struct  MultiXactMember
 
struct  xl_multixact_create
 
struct  xl_multixact_truncate
 

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Macro Definition Documentation

◆ FirstMultiXactId

◆ InvalidMultiXactId

◆ ISUPDATE_from_mxstatus

◆ MaxMultiXactId

#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)

Definition at line 26 of file multixact.h.

Referenced by SetMultiXactIdLimit().

◆ MaxMultiXactOffset

#define MaxMultiXactOffset   ((MultiXactOffset) 0xFFFFFFFF)

Definition at line 30 of file multixact.h.

Referenced by ExtendMultiXactMember(), and PerformMembersTruncation().

◆ MaxMultiXactStatus

#define MaxMultiXactStatus   MultiXactStatusUpdate

Definition at line 53 of file multixact.h.

◆ MultiXactIdIsValid

◆ NUM_MULTIXACTMEMBER_BUFFERS

#define NUM_MULTIXACTMEMBER_BUFFERS   16

Definition at line 34 of file multixact.h.

Referenced by MultiXactShmemInit(), and MultiXactShmemSize().

◆ NUM_MULTIXACTOFFSET_BUFFERS

#define NUM_MULTIXACTOFFSET_BUFFERS   8

Definition at line 33 of file multixact.h.

Referenced by MultiXactShmemInit(), and MultiXactShmemSize().

◆ SizeOfMultiXactCreate

#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Definition at line 85 of file multixact.h.

Referenced by MultiXactIdCreateFromMembers().

◆ SizeOfMultiXactTruncate

#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))

Definition at line 100 of file multixact.h.

Referenced by multixact_redo(), and WriteMTruncateXlogRec().

◆ XLOG_MULTIXACT_CREATE_ID

#define XLOG_MULTIXACT_CREATE_ID   0x20

◆ XLOG_MULTIXACT_TRUNCATE_ID

#define XLOG_MULTIXACT_TRUNCATE_ID   0x30

◆ XLOG_MULTIXACT_ZERO_MEM_PAGE

#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10

◆ XLOG_MULTIXACT_ZERO_OFF_PAGE

#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00

Typedef Documentation

◆ MultiXactMember

◆ xl_multixact_create

◆ xl_multixact_truncate

Enumeration Type Documentation

◆ MultiXactStatus

Enumerator
MultiXactStatusForKeyShare 
MultiXactStatusForShare 
MultiXactStatusForNoKeyUpdate 
MultiXactStatusForUpdate 
MultiXactStatusNoKeyUpdate 
MultiXactStatusUpdate 

Definition at line 41 of file multixact.h.

42 {
47  /* an update that doesn't touch "key" columns */
49  /* other updates, and delete */
MultiXactStatus
Definition: multixact.h:41

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1683 of file multixact.c.

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

Referenced by AbortTransaction(), and CommitTransaction().

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

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1712 of file multixact.c.

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

Referenced by PrepareTransaction().

1713 {
1714  MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1715 
1716  if (MultiXactIdIsValid(myOldestMember))
1718  &myOldestMember, sizeof(MultiXactId));
1719 }
BackendId MyBackendId
Definition: globals.c:82
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1182
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27
TransactionId MultiXactId
Definition: c.h:597

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1891 of file multixact.c.

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

Referenced by BootStrapXLOG().

1892 {
1893  int slotno;
1894 
1895  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1896 
1897  /* Create and zero the first page of the offsets log */
1898  slotno = ZeroMultiXactOffsetPage(0, false);
1899 
1900  /* Make sure it's written out */
1902  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1903 
1904  LWLockRelease(MultiXactOffsetSLRULock);
1905 
1906  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
1907 
1908  /* Create and zero the first page of the members log */
1909  slotno = ZeroMultiXactMemberPage(0, false);
1910 
1911  /* Make sure it's written out */
1913  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1914 
1915  LWLockRelease(MultiXactMemberSLRULock);
1916 }
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1928
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:613
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1944
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2152 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

2153 {
2154  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2155 
2156  /*
2157  * Write dirty MultiXact pages to disk. This may result in sync requests
2158  * queued for later handling by ProcessSyncRequests(), as part of the
2159  * checkpoint.
2160  */
2163 
2164  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2165 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1155
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ GetMultiXactIdMembers()

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

Definition at line 1223 of file multixact.c.

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

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

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

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2503 of file multixact.c.

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

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

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

◆ multixact_desc()

void multixact_desc ( StringInfo  buf,
XLogReaderState record 
)

Definition at line 50 of file mxactdesc.c.

References appendStringInfo(), 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.

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

◆ multixact_identify()

const char* multixact_identify ( uint8  info)

Definition at line 84 of file mxactdesc.c.

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

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 }
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:73
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:74
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:72
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:75

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 3233 of file multixact.c.

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

3234 {
3235  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3236 
3237  /* Backup blocks are not used in multixact records */
3238  Assert(!XLogRecHasAnyBlockRefs(record));
3239 
3240  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3241  {
3242  int pageno;
3243  int slotno;
3244 
3245  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3246 
3247  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
3248 
3249  slotno = ZeroMultiXactOffsetPage(pageno, false);
3251  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3252 
3253  LWLockRelease(MultiXactOffsetSLRULock);
3254  }
3255  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3256  {
3257  int pageno;
3258  int slotno;
3259 
3260  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3261 
3262  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
3263 
3264  slotno = ZeroMultiXactMemberPage(pageno, false);
3266  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3267 
3268  LWLockRelease(MultiXactMemberSLRULock);
3269  }
3270  else if (info == XLOG_MULTIXACT_CREATE_ID)
3271  {
3272  xl_multixact_create *xlrec =
3273  (xl_multixact_create *) XLogRecGetData(record);
3274  TransactionId max_xid;
3275  int i;
3276 
3277  /* Store the data back into the SLRU files */
3278  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3279  xlrec->members);
3280 
3281  /* Make sure nextMXact/nextOffset are beyond what this record has */
3282  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3283  xlrec->moff + xlrec->nmembers);
3284 
3285  /*
3286  * Make sure nextXid is beyond any XID mentioned in the record.
3287  * This should be unnecessary, since any XID found here ought to have
3288  * other evidence in the XLOG, but let's be safe.
3289  */
3290  max_xid = XLogRecGetXid(record);
3291  for (i = 0; i < xlrec->nmembers; i++)
3292  {
3293  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3294  max_xid = xlrec->members[i].xid;
3295  }
3296 
3298  }
3299  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3300  {
3301  xl_multixact_truncate xlrec;
3302  int pageno;
3303 
3304  memcpy(&xlrec, XLogRecGetData(record),
3306 
3307  elog(DEBUG1, "replaying multixact truncation: "
3308  "offsets [%u, %u), offsets segments [%x, %x), "
3309  "members [%u, %u), members segments [%x, %x)",
3310  xlrec.startTruncOff, xlrec.endTruncOff,
3313  xlrec.startTruncMemb, xlrec.endTruncMemb,
3316 
3317  /* should not be required, but more than cheap enough */
3318  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3319 
3320  /*
3321  * Advance the horizon values, so they're current at the end of
3322  * recovery.
3323  */
3324  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3325 
3327 
3328  /*
3329  * During XLOG replay, latest_page_number isn't necessarily set up
3330  * yet; insert a suitable value to bypass the sanity test in
3331  * SimpleLruTruncate.
3332  */
3333  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3334  MultiXactOffsetCtl->shared->latest_page_number = pageno;
3336 
3337  LWLockRelease(MultiXactTruncationLock);
3338  }
3339  else
3340  elog(PANIC, "multixact_redo: unknown op code %u", info);
3341 }
#define DEBUG1
Definition: elog.h:25
uint32 TransactionId
Definition: c.h:587
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:277
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1928
unsigned char uint8
Definition: c.h:439
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:73
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2359
#define PANIC
Definition: elog.h:55
#define SizeOfMultiXactTruncate
Definition: multixact.h:100
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:82
#define XLogRecGetData(decoder)
Definition: xlogreader.h:310
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:74
TransactionId xid
Definition: multixact.h:62
MultiXactOffset moff
Definition: multixact.h:80
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2888
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:613
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:305
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
MultiXactOffset endTruncMemb
Definition: multixact.h:97
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:307
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:72
MultiXactOffset startTruncMemb
Definition: multixact.h:96
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2210
MultiXactId mid
Definition: multixact.h:79
#define Assert(condition)
Definition: c.h:804
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:75
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
MultiXactId startTruncOff
Definition: multixact.h:92
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1944
#define elog(elevel,...)
Definition: elog.h:228
int i
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:312
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:862
MultiXactId endTruncOff
Definition: multixact.h:93
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2916
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ multixact_twophase_postabort()

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

Definition at line 1812 of file multixact.c.

References multixact_twophase_postcommit().

1814 {
1815  multixact_twophase_postcommit(xid, info, recdata, len);
1816 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1797

◆ multixact_twophase_postcommit()

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

Definition at line 1797 of file multixact.c.

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

Referenced by multixact_twophase_postabort().

1799 {
1800  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, true);
1801 
1802  Assert(len == sizeof(MultiXactId));
1803 
1804  OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
1805 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:859
int BackendId
Definition: backendid.h:21
#define InvalidMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:597
#define Assert(condition)
Definition: c.h:804

◆ multixact_twophase_recover()

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

Definition at line 1776 of file multixact.c.

References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

1778 {
1779  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1780  MultiXactId oldestMember;
1781 
1782  /*
1783  * Get the oldest member XID from the state file record, and set it in the
1784  * OldestMemberMXactId slot reserved for this prepared transaction.
1785  */
1786  Assert(len == sizeof(MultiXactId));
1787  oldestMember = *((MultiXactId *) recdata);
1788 
1789  OldestMemberMXactId[dummyBackendId] = oldestMember;
1790 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:859
int BackendId
Definition: backendid.h:21
TransactionId MultiXactId
Definition: c.h:597
#define Assert(condition)
Definition: c.h:804

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2359 of file multixact.c.

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

Referenced by multixact_redo(), and xlog_redo().

2361 {
2362  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2364  {
2365  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2366  MultiXactState->nextMXact = minMulti;
2367  }
2368  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2369  {
2370  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2371  minMultiOffset);
2372  MultiXactState->nextOffset = minMultiOffset;
2373  }
2374  LWLockRelease(MultiXactGenLock);
2375 }
MultiXactId nextMXact
Definition: multixact.c:203
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define DEBUG2
Definition: elog.h:24
#define debug_elog3(a, b, c)
Definition: multixact.c:334
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3156
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3182

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2384 of file multixact.c.

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

Referenced by xlog_redo().

2385 {
2386  Assert(InRecovery);
2387 
2389  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2390 }
bool InRecovery
Definition: xlog.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
MultiXactId oldestMultiXactId
Definition: multixact.c:216
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2210
#define Assert(condition)
Definition: c.h:804
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3156

◆ MultiXactGetCheckptMulti()

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

Definition at line 2130 of file multixact.c.

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

Referenced by CreateCheckPoint().

2135 {
2136  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2137  *nextMulti = MultiXactState->nextMXact;
2138  *nextMultiOffset = MultiXactState->nextOffset;
2139  *oldestMulti = MultiXactState->oldestMultiXactId;
2140  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2141  LWLockRelease(MultiXactGenLock);
2142 
2144  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2145  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2146 }
MultiXactId nextMXact
Definition: multixact.c:203
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:337
#define DEBUG2
Definition: elog.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206

◆ MultiXactIdCreate()

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

Definition at line 386 of file multixact.c.

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

Referenced by compute_new_xmax_infomask().

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

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 767 of file multixact.c.

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

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

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

◆ MultiXactIdExpand()

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

Definition at line 439 of file multixact.c.

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

Referenced by compute_new_xmax_infomask().

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

◆ MultiXactIdIsRunning()

bool MultiXactIdIsRunning ( MultiXactId  multi,
bool  isLockOnly 
)

Definition at line 551 of file multixact.c.

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

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

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

◆ MultiXactIdPrecedes()

◆ MultiXactIdPrecedesOrEquals()

bool MultiXactIdPrecedesOrEquals ( MultiXactId  multi1,
MultiXactId  multi2 
)

Definition at line 3170 of file multixact.c.

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

3171 {
3172  int32 diff = (int32) (multi1 - multi2);
3173 
3174  return (diff <= 0);
3175 }
signed int int32
Definition: c.h:429

◆ MultiXactIdSetOldestMember()

void MultiXactIdSetOldestMember ( void  )

Definition at line 625 of file multixact.c.

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

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

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

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2825 of file multixact.c.

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

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

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

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3421 of file multixact.c.

References MultiXactMemberCtl, and SlruSyncFileTag().

3422 {
3423  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3424 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1592
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3412 of file multixact.c.

References MultiXactOffsetCtl, and SlruSyncFileTag().

3413 {
3414  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3415 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1592
#define MultiXactOffsetCtl
Definition: multixact.c:190

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2176 of file multixact.c.

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

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

2178 {
2179  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2180  nextMulti, nextMultiOffset);
2181  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2182  MultiXactState->nextMXact = nextMulti;
2183  MultiXactState->nextOffset = nextMultiOffset;
2184  LWLockRelease(MultiXactGenLock);
2185 
2186  /*
2187  * During a binary upgrade, make sure that the offsets SLRU is large
2188  * enough to contain the next value that would be created.
2189  *
2190  * We need to do this pretty early during the first startup in binary
2191  * upgrade mode: before StartupMultiXact() in fact, because this routine
2192  * is called even before that by StartupXLOG(). And we can't do it
2193  * earlier than at this point, because during that first call of this
2194  * routine we determine the MultiXactState->nextMXact value that
2195  * MaybeExtendOffsetSlru needs.
2196  */
2197  if (IsBinaryUpgrade)
2199 }
MultiXactId nextMXact
Definition: multixact.c:203
#define debug_elog4(a, b, c, d)
Definition: multixact.c:335
MultiXactOffset nextOffset
Definition: multixact.c:206
static void MaybeExtendOffsetSlru(void)
Definition: multixact.c:1972
bool IsBinaryUpgrade
Definition: globals.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define DEBUG2
Definition: elog.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206

◆ MultiXactShmemInit()

void MultiXactShmemInit ( void  )

Definition at line 1841 of file multixact.c.

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

Referenced by CreateSharedMemoryAndSemaphores().

1842 {
1843  bool found;
1844 
1845  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1846 
1849 
1851  "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
1852  MultiXactOffsetSLRULock, "pg_multixact/offsets",
1857  "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
1858  MultiXactMemberSLRULock, "pg_multixact/members",
1861  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1862 
1863  /* Initialize our shared state struct */
1864  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1866  &found);
1867  if (!IsUnderPostmaster)
1868  {
1869  Assert(!found);
1870 
1871  /* Make sure we zero out the per-backend state */
1873  }
1874  else
1875  Assert(found);
1876 
1877  /*
1878  * Set up array pointers. Note that perBackendXactIds[0] is wasted space
1879  * since we only use indexes 1..MaxOldestSlot in each array.
1880  */
1883 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:281
static bool MultiXactOffsetPagePrecedes(int page1, int page2)
Definition: multixact.c:3116
#define MemSet(start, val, len)
Definition: c.h:1008
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
#define NUM_MULTIXACTOFFSET_BUFFERS
Definition: multixact.h:33
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id, SyncRequestHandler sync_handler)
Definition: slru.c:186
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
#define DEBUG2
Definition: elog.h:24
bool IsUnderPostmaster
Definition: globals.c:110
#define debug_elog2(a, b)
Definition: multixact.c:333
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
static bool MultiXactMemberPagePrecedes(int page1, int page2)
Definition: multixact.c:3136
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:804
#define MaxOldestSlot
Definition: multixact.c:288
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:156
#define MultiXactMemberCtl
Definition: multixact.c:191
#define SHARED_MULTIXACT_STATE_SIZE
#define NUM_MULTIXACTMEMBER_BUFFERS
Definition: multixact.h:34

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1824 of file multixact.c.

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

Referenced by CreateSharedMemoryAndSemaphores().

1825 {
1826  Size size;
1827 
1828  /* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
1829 #define SHARED_MULTIXACT_STATE_SIZE \
1830  add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
1831  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1832 
1836 
1837  return size;
1838 }
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:155
#define NUM_MULTIXACTOFFSET_BUFFERS
Definition: multixact.h:33
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
size_t Size
Definition: c.h:540
#define SHARED_MULTIXACT_STATE_SIZE
#define NUM_MULTIXACTMEMBER_BUFFERS
Definition: multixact.h:34

◆ mxid_to_string()

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

Definition at line 1652 of file multixact.c.

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

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

1653 {
1654  static char *str = NULL;
1656  int i;
1657 
1658  if (str != NULL)
1659  pfree(str);
1660 
1661  initStringInfo(&buf);
1662 
1663  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1664  mxstatus_to_string(members[0].status));
1665 
1666  for (i = 1; i < nmembers; i++)
1667  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1668  mxstatus_to_string(members[i].status));
1669 
1670  appendStringInfoChar(&buf, ']');
1672  pfree(buf.data);
1673  return str;
1674 }
void pfree(void *pointer)
Definition: mcxt.c:1057
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
static char * buf
Definition: pg_test_fsync.c:68
MemoryContext TopMemoryContext
Definition: mcxt.c:44
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1174
int i
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1629
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1726 of file multixact.c.

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

Referenced by PrepareTransaction().

1727 {
1728  MultiXactId myOldestMember;
1729 
1730  /*
1731  * Transfer our OldestMemberMXactId value to the slot reserved for the
1732  * prepared transaction.
1733  */
1734  myOldestMember = OldestMemberMXactId[MyBackendId];
1735  if (MultiXactIdIsValid(myOldestMember))
1736  {
1737  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1738 
1739  /*
1740  * Even though storing MultiXactId is atomic, acquire lock to make
1741  * sure others see both changes, not just the reset of the slot of the
1742  * current backend. Using a volatile pointer might suffice, but this
1743  * isn't a hot spot.
1744  */
1745  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1746 
1747  OldestMemberMXactId[dummyBackendId] = myOldestMember;
1749 
1750  LWLockRelease(MultiXactGenLock);
1751  }
1752 
1753  /*
1754  * We don't need to transfer OldestVisibleMXactId value, because the
1755  * transaction is not going to be looking at any more multixacts once it's
1756  * prepared.
1757  *
1758  * We assume that storing a MultiXactId is atomic and so we need not take
1759  * MultiXactGenLock to do this.
1760  */
1762 
1763  /*
1764  * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1765  */
1766  MXactContext = NULL;
1768  MXactCacheMembers = 0;
1769 }
BackendId MyBackendId
Definition: globals.c:82
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
static int MXactCacheMembers
Definition: multixact.c:323
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:859
int BackendId
Definition: backendid.h:21
#define InvalidMultiXactId
Definition: multixact.h:24
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
TransactionId MultiXactId
Definition: c.h:597
static dlist_head MXactCache
Definition: multixact.c:322
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
static MemoryContext MXactContext
Definition: multixact.c:324

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 743 of file multixact.c.

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

Referenced by update_cached_mxid_range().

744 {
745  LWLockAcquire(MultiXactGenLock, LW_SHARED);
748  LWLockRelease(MultiXactGenLock);
749 
750  if (*oldest < FirstMultiXactId)
751  *oldest = FirstMultiXactId;
752  if (*next < FirstMultiXactId)
754 }
MultiXactId nextMXact
Definition: multixact.c:203
static int32 next
Definition: blutils.c:219
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define FirstMultiXactId
Definition: multixact.h:25
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206

◆ ReadNextMultiXactId()

MultiXactId ReadNextMultiXactId ( void  )

Definition at line 723 of file multixact.c.

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

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

724 {
725  MultiXactId mxid;
726 
727  /* XXX we could presumably do this without a lock. */
728  LWLockAcquire(MultiXactGenLock, LW_SHARED);
729  mxid = MultiXactState->nextMXact;
730  LWLockRelease(MultiXactGenLock);
731 
732  if (mxid < FirstMultiXactId)
733  mxid = FirstMultiXactId;
734 
735  return mxid;
736 }
MultiXactId nextMXact
Definition: multixact.c:203
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define FirstMultiXactId
Definition: multixact.h:25
TransactionId MultiXactId
Definition: c.h:597
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206

◆ SetMultiXactIdLimit()

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

Definition at line 2210 of file multixact.c.

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

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

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2005 of file multixact.c.

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

Referenced by StartupXLOG().

2006 {
2009  int pageno;
2010 
2011  /*
2012  * Initialize offset's idea of the latest page number.
2013  */
2014  pageno = MultiXactIdToOffsetPage(multi);
2015  MultiXactOffsetCtl->shared->latest_page_number = pageno;
2016 
2017  /*
2018  * Initialize member's idea of the latest page number.
2019  */
2020  pageno = MXOffsetToMemberPage(offset);
2021  MultiXactMemberCtl->shared->latest_page_number = pageno;
2022 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:599
MultiXactOffset nextOffset
Definition: multixact.c:206
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
#define MultiXactOffsetCtl
Definition: multixact.c:190
TransactionId MultiXactId
Definition: c.h:597
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 2028 of file multixact.c.

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

Referenced by StartupXLOG().

2029 {
2030  MultiXactId nextMXact;
2031  MultiXactOffset offset;
2032  MultiXactId oldestMXact;
2033  Oid oldestMXactDB;
2034  int pageno;
2035  int entryno;
2036  int flagsoff;
2037 
2038  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2039  nextMXact = MultiXactState->nextMXact;
2040  offset = MultiXactState->nextOffset;
2041  oldestMXact = MultiXactState->oldestMultiXactId;
2042  oldestMXactDB = MultiXactState->oldestMultiXactDB;
2043  LWLockRelease(MultiXactGenLock);
2044 
2045  /* Clean up offsets state */
2046  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
2047 
2048  /*
2049  * (Re-)Initialize our idea of the latest page number for offsets.
2050  */
2051  pageno = MultiXactIdToOffsetPage(nextMXact);
2052  MultiXactOffsetCtl->shared->latest_page_number = pageno;
2053 
2054  /*
2055  * Zero out the remainder of the current offsets page. See notes in
2056  * TrimCLOG() for background. Unlike CLOG, some WAL record covers every
2057  * pg_multixact SLRU mutation. Since, also unlike CLOG, we ignore the WAL
2058  * rule "write xlog before data," nextMXact successors may carry obsolete,
2059  * nonzero offset values. Zero those so case 2 of GetMultiXactIdMembers()
2060  * operates normally.
2061  */
2062  entryno = MultiXactIdToOffsetEntry(nextMXact);
2063  if (entryno != 0)
2064  {
2065  int slotno;
2066  MultiXactOffset *offptr;
2067 
2068  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2069  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2070  offptr += entryno;
2071 
2072  MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
2073 
2074  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2075  }
2076 
2077  LWLockRelease(MultiXactOffsetSLRULock);
2078 
2079  /* And the same for members */
2080  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
2081 
2082  /*
2083  * (Re-)Initialize our idea of the latest page number for members.
2084  */
2085  pageno = MXOffsetToMemberPage(offset);
2086  MultiXactMemberCtl->shared->latest_page_number = pageno;
2087 
2088  /*
2089  * Zero out the remainder of the current members page. See notes in
2090  * TrimCLOG() for motivation.
2091  */
2092  flagsoff = MXOffsetToFlagsOffset(offset);
2093  if (flagsoff != 0)
2094  {
2095  int slotno;
2096  TransactionId *xidptr;
2097  int memberoff;
2098 
2099  memberoff = MXOffsetToMemberOffset(offset);
2100  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2101  xidptr = (TransactionId *)
2102  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2103 
2104  MemSet(xidptr, 0, BLCKSZ - memberoff);
2105 
2106  /*
2107  * Note: we don't need to zero out the flag bits in the remaining
2108  * members of the current group, because they are always reset before
2109  * writing.
2110  */
2111 
2112  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2113  }
2114 
2115  LWLockRelease(MultiXactMemberSLRULock);
2116 
2117  /* signal that we're officially up */
2118  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2120  LWLockRelease(MultiXactGenLock);
2121 
2122  /* Now compute how far away the next members wraparound is. */
2123  SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2124 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:599
uint32 TransactionId
Definition: c.h:587
MultiXactOffset nextOffset
Definition: multixact.c:206
#define MemSet(start, val, len)
Definition: c.h:1008
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
unsigned int Oid
Definition: postgres_ext.h:31
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define MXOffsetToMemberOffset(xid)
Definition: multixact.c:172
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:394
#define MultiXactOffsetCtl
Definition: multixact.c:190
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2210
TransactionId MultiXactId
Definition: c.h:597
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2941 of file multixact.c.

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

Referenced by vac_truncate_clog().

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