PostgreSQL Source Code  git master
multixact.h File Reference
#include "access/xlogreader.h"
#include "lib/stringinfo.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_MXACTOFFSET_BUFFERS   8
 
#define NUM_MXACTMEMBER_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)
 
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)
 
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 ShutdownMultiXact (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 25 of file multixact.h.

Referenced by SetMultiXactIdLimit().

◆ MaxMultiXactOffset

#define MaxMultiXactOffset   ((MultiXactOffset) 0xFFFFFFFF)

Definition at line 29 of file multixact.h.

Referenced by ExtendMultiXactMember(), and PerformMembersTruncation().

◆ MaxMultiXactStatus

#define MaxMultiXactStatus   MultiXactStatusUpdate

Definition at line 52 of file multixact.h.

◆ MultiXactIdIsValid

◆ NUM_MXACTMEMBER_BUFFERS

#define NUM_MXACTMEMBER_BUFFERS   16

Definition at line 33 of file multixact.h.

Referenced by MultiXactShmemInit(), and MultiXactShmemSize().

◆ NUM_MXACTOFFSET_BUFFERS

#define NUM_MXACTOFFSET_BUFFERS   8

Definition at line 32 of file multixact.h.

Referenced by MultiXactShmemInit(), and MultiXactShmemSize().

◆ SizeOfMultiXactCreate

#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Definition at line 84 of file multixact.h.

Referenced by MultiXactIdCreateFromMembers().

◆ SizeOfMultiXactTruncate

#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))

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

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

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1664 of file multixact.c.

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

Referenced by AbortTransaction(), and CommitTransaction().

1665 {
1666  /*
1667  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1668  * which should only be valid while within a transaction.
1669  *
1670  * We assume that storing a MultiXactId is atomic and so we need not take
1671  * MultiXactGenLock to do this.
1672  */
1675 
1676  /*
1677  * Discard the local MultiXactId cache. Since MXactContext was created as
1678  * a child of TopTransactionContext, we needn't delete it explicitly.
1679  */
1680  MXactContext = NULL;
1682  MXactCacheMembers = 0;
1683 }
BackendId MyBackendId
Definition: globals.c:81
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:23
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 1693 of file multixact.c.

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

Referenced by PrepareTransaction().

1694 {
1695  MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1696 
1697  if (MultiXactIdIsValid(myOldestMember))
1699  &myOldestMember, sizeof(MultiXactId));
1700 }
BackendId MyBackendId
Definition: globals.c:81
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1187
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27
TransactionId MultiXactId
Definition: c.h:518

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1868 of file multixact.c.

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

Referenced by BootStrapXLOG().

1869 {
1870  int slotno;
1871 
1872  LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
1873 
1874  /* Create and zero the first page of the offsets log */
1875  slotno = ZeroMultiXactOffsetPage(0, false);
1876 
1877  /* Make sure it's written out */
1879  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1880 
1881  LWLockRelease(MultiXactOffsetControlLock);
1882 
1883  LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
1884 
1885  /* Create and zero the first page of the members log */
1886  slotno = ZeroMultiXactMemberPage(0, false);
1887 
1888  /* Make sure it's written out */
1890  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1891 
1892  LWLockRelease(MultiXactMemberControlLock);
1893 }
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1905
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:577
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:733
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1921
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2142 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().

Referenced by CheckPointGuts().

2143 {
2144  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2145 
2146  /* Flush dirty MultiXact pages to disk */
2149 
2150  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2151 }
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1119
#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 1204 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().

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

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2493 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().

2494 {
2495  MultiXactId oldestMXact;
2496  MultiXactId nextMXact;
2497  int i;
2498 
2499  /*
2500  * This is the oldest valid value among all the OldestMemberMXactId[] and
2501  * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2502  */
2503  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2504 
2505  /*
2506  * We have to beware of the possibility that nextMXact is in the
2507  * wrapped-around state. We don't fix the counter itself here, but we
2508  * must be sure to use a valid value in our calculation.
2509  */
2510  nextMXact = MultiXactState->nextMXact;
2511  if (nextMXact < FirstMultiXactId)
2512  nextMXact = FirstMultiXactId;
2513 
2514  oldestMXact = nextMXact;
2515  for (i = 1; i <= MaxOldestSlot; i++)
2516  {
2517  MultiXactId thisoldest;
2518 
2519  thisoldest = OldestMemberMXactId[i];
2520  if (MultiXactIdIsValid(thisoldest) &&
2521  MultiXactIdPrecedes(thisoldest, oldestMXact))
2522  oldestMXact = thisoldest;
2523  thisoldest = OldestVisibleMXactId[i];
2524  if (MultiXactIdIsValid(thisoldest) &&
2525  MultiXactIdPrecedes(thisoldest, oldestMXact))
2526  oldestMXact = thisoldest;
2527  }
2528 
2529  LWLockRelease(MultiXactGenLock);
2530 
2531  return oldestMXact;
2532 }
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:1726
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define FirstMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:518
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3142
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:357
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:72
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:81
#define XLogRecGetData(decoder)
Definition: xlogreader.h:246
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:73
MultiXactOffset moff
Definition: multixact.h:79
static void out_member(StringInfo buf, MultiXactMember *member)
Definition: mxactdesc.c:20
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:242
MultiXactOffset endTruncMemb
Definition: multixact.h:96
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:71
MultiXactOffset startTruncMemb
Definition: multixact.h:95
MultiXactId mid
Definition: multixact.h:78
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:74
MultiXactId startTruncOff
Definition: multixact.h:91
int i
MultiXactId endTruncOff
Definition: multixact.h:92

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

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 3219 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().

3220 {
3221  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3222 
3223  /* Backup blocks are not used in multixact records */
3224  Assert(!XLogRecHasAnyBlockRefs(record));
3225 
3226  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3227  {
3228  int pageno;
3229  int slotno;
3230 
3231  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3232 
3233  LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
3234 
3235  slotno = ZeroMultiXactOffsetPage(pageno, false);
3237  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3238 
3239  LWLockRelease(MultiXactOffsetControlLock);
3240  }
3241  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3242  {
3243  int pageno;
3244  int slotno;
3245 
3246  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3247 
3248  LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
3249 
3250  slotno = ZeroMultiXactMemberPage(pageno, false);
3252  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3253 
3254  LWLockRelease(MultiXactMemberControlLock);
3255  }
3256  else if (info == XLOG_MULTIXACT_CREATE_ID)
3257  {
3258  xl_multixact_create *xlrec =
3259  (xl_multixact_create *) XLogRecGetData(record);
3260  TransactionId max_xid;
3261  int i;
3262 
3263  /* Store the data back into the SLRU files */
3264  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3265  xlrec->members);
3266 
3267  /* Make sure nextMXact/nextOffset are beyond what this record has */
3268  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3269  xlrec->moff + xlrec->nmembers);
3270 
3271  /*
3272  * Make sure nextFullXid is beyond any XID mentioned in the record.
3273  * This should be unnecessary, since any XID found here ought to have
3274  * other evidence in the XLOG, but let's be safe.
3275  */
3276  max_xid = XLogRecGetXid(record);
3277  for (i = 0; i < xlrec->nmembers; i++)
3278  {
3279  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3280  max_xid = xlrec->members[i].xid;
3281  }
3282 
3284  }
3285  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3286  {
3287  xl_multixact_truncate xlrec;
3288  int pageno;
3289 
3290  memcpy(&xlrec, XLogRecGetData(record),
3292 
3293  elog(DEBUG1, "replaying multixact truncation: "
3294  "offsets [%u, %u), offsets segments [%x, %x), "
3295  "members [%u, %u), members segments [%x, %x)",
3296  xlrec.startTruncOff, xlrec.endTruncOff,
3299  xlrec.startTruncMemb, xlrec.endTruncMemb,
3302 
3303  /* should not be required, but more than cheap enough */
3304  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3305 
3306  /*
3307  * Advance the horizon values, so they're current at the end of
3308  * recovery.
3309  */
3310  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3311 
3313 
3314  /*
3315  * During XLOG replay, latest_page_number isn't necessarily set up
3316  * yet; insert a suitable value to bypass the sanity test in
3317  * SimpleLruTruncate.
3318  */
3319  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3320  MultiXactOffsetCtl->shared->latest_page_number = pageno;
3322 
3323  LWLockRelease(MultiXactTruncationLock);
3324  }
3325  else
3326  elog(PANIC, "multixact_redo: unknown op code %u", info);
3327 }
#define DEBUG1
Definition: elog.h:25
uint32 TransactionId
Definition: c.h:508
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:262
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1905
unsigned char uint8
Definition: c.h:357
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:72
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2349
#define PANIC
Definition: elog.h:53
#define SizeOfMultiXactTruncate
Definition: multixact.h:99
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:81
#define XLogRecGetData(decoder)
Definition: xlogreader.h:246
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:73
TransactionId xid
Definition: multixact.h:61
MultiXactOffset moff
Definition: multixact.h:79
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2882
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:577
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:242
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
MultiXactOffset endTruncMemb
Definition: multixact.h:96
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:244
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:71
MultiXactOffset startTruncMemb
Definition: multixact.h:95
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2196
MultiXactId mid
Definition: multixact.h:78
#define Assert(condition)
Definition: c.h:733
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:74
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
MultiXactId startTruncOff
Definition: multixact.h:91
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1921
#define elog(elevel,...)
Definition: elog.h:228
int i
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:248
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:843
MultiXactId endTruncOff
Definition: multixact.h:92
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2910
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ multixact_twophase_postabort()

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

Definition at line 1793 of file multixact.c.

References multixact_twophase_postcommit().

1795 {
1796  multixact_twophase_postcommit(xid, info, recdata, len);
1797 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1778

◆ multixact_twophase_postcommit()

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

Definition at line 1778 of file multixact.c.

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

Referenced by multixact_twophase_postabort().

1780 {
1781  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, true);
1782 
1783  Assert(len == sizeof(MultiXactId));
1784 
1785  OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
1786 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:863
int BackendId
Definition: backendid.h:21
#define InvalidMultiXactId
Definition: multixact.h:23
TransactionId MultiXactId
Definition: c.h:518
#define Assert(condition)
Definition: c.h:733

◆ multixact_twophase_recover()

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

Definition at line 1757 of file multixact.c.

References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

1759 {
1760  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1761  MultiXactId oldestMember;
1762 
1763  /*
1764  * Get the oldest member XID from the state file record, and set it in the
1765  * OldestMemberMXactId slot reserved for this prepared transaction.
1766  */
1767  Assert(len == sizeof(MultiXactId));
1768  oldestMember = *((MultiXactId *) recdata);
1769 
1770  OldestMemberMXactId[dummyBackendId] = oldestMember;
1771 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:863
int BackendId
Definition: backendid.h:21
TransactionId MultiXactId
Definition: c.h:518
#define Assert(condition)
Definition: c.h:733

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2349 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().

2351 {
2352  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2354  {
2355  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2356  MultiXactState->nextMXact = minMulti;
2357  }
2358  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2359  {
2360  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2361  minMultiOffset);
2362  MultiXactState->nextOffset = minMultiOffset;
2363  }
2364  LWLockRelease(MultiXactGenLock);
2365 }
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:1726
#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:1122
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3142
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3168

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2374 of file multixact.c.

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

Referenced by xlog_redo().

2375 {
2376  Assert(InRecovery);
2377 
2379  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2380 }
bool InRecovery
Definition: xlog.c:200
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:2196
#define Assert(condition)
Definition: c.h:733
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3142

◆ MultiXactGetCheckptMulti()

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

Definition at line 2120 of file multixact.c.

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

Referenced by CreateCheckPoint().

2125 {
2126  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2127  *nextMulti = MultiXactState->nextMXact;
2128  *nextMultiOffset = MultiXactState->nextOffset;
2129  *oldestMulti = MultiXactState->oldestMultiXactId;
2130  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2131  LWLockRelease(MultiXactGenLock);
2132 
2134  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2135  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2136 }
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:1726
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:1122

◆ 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:81
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:748
TransactionId xid
Definition: multixact.h:61
#define DEBUG2
Definition: elog.h:24
MultiXactStatus status
Definition: multixact.h:62
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1633
#define AssertArg(condition)
Definition: c.h:735
#define debug_elog3(a, b, c)
Definition: multixact.c:334
TransactionId MultiXactId
Definition: c.h:518
#define Assert(condition)
Definition: c.h:733
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 748 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().

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

◆ 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, member, 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  {
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:81
#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:987
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:748
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
Oid member
void pfree(void *pointer)
Definition: mcxt.c:1056
TransactionId xid
Definition: multixact.h:61
#define DEBUG2
Definition: elog.h:24
MultiXactStatus status
Definition: multixact.h:62
#define ISUPDATE_from_mxstatus(status)
Definition: multixact.h:55
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define AssertArg(condition)
Definition: c.h:735
#define debug_elog3(a, b, c)
Definition: multixact.c:334
TransactionId MultiXactId
Definition: c.h:518
#define Assert(condition)
Definition: c.h:733
void * palloc(Size size)
Definition: mcxt.c:949
int i
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1610
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1204
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226
#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 HeapTupleSatisfiesVacuum().

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:853
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:987
void pfree(void *pointer)
Definition: mcxt.c:1056
#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:1204

◆ MultiXactIdPrecedes()

◆ MultiXactIdPrecedesOrEquals()

bool MultiXactIdPrecedesOrEquals ( MultiXactId  multi1,
MultiXactId  multi2 
)

Definition at line 3156 of file multixact.c.

Referenced by heap_vacuum_rel(), and TruncateMultiXact().

3157 {
3158  int32 diff = (int32) (multi1 - multi2);
3159 
3160  return (diff <= 0);
3161 }
signed int int32
Definition: c.h:347

◆ 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:81
#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:1726
#define DEBUG2
Definition: elog.h:24
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define FirstMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:518
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2819 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().

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

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2162 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().

2164 {
2165  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2166  nextMulti, nextMultiOffset);
2167  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2168  MultiXactState->nextMXact = nextMulti;
2169  MultiXactState->nextOffset = nextMultiOffset;
2170  LWLockRelease(MultiXactGenLock);
2171 
2172  /*
2173  * During a binary upgrade, make sure that the offsets SLRU is large
2174  * enough to contain the next value that would be created.
2175  *
2176  * We need to do this pretty early during the first startup in binary
2177  * upgrade mode: before StartupMultiXact() in fact, because this routine
2178  * is called even before that by StartupXLOG(). And we can't do it
2179  * earlier than at this point, because during that first call of this
2180  * routine we determine the MultiXactState->nextMXact value that
2181  * MaybeExtendOffsetSlru needs.
2182  */
2183  if (IsBinaryUpgrade)
2185 }
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:1949
bool IsBinaryUpgrade
Definition: globals.c:110
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define DEBUG2
Definition: elog.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122

◆ MultiXactShmemInit()

void MultiXactShmemInit ( void  )

Definition at line 1822 of file multixact.c.

References Assert, DEBUG2, debug_elog2, IsUnderPostmaster, LWTRANCHE_MXACTMEMBER_BUFFERS, LWTRANCHE_MXACTOFFSET_BUFFERS, MaxOldestSlot, MemSet, MultiXactMemberCtl, MultiXactMemberPagePrecedes(), MultiXactOffsetCtl, MultiXactOffsetPagePrecedes(), NUM_MXACTMEMBER_BUFFERS, NUM_MXACTOFFSET_BUFFERS, OldestMemberMXactId, OldestVisibleMXactId, MultiXactStateData::perBackendXactIds, SHARED_MULTIXACT_STATE_SIZE, ShmemInitStruct(), and SimpleLruInit().

Referenced by CreateSharedMemoryAndSemaphores().

1823 {
1824  bool found;
1825 
1826  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1827 
1830 
1832  "multixact_offset", NUM_MXACTOFFSET_BUFFERS, 0,
1833  MultiXactOffsetControlLock, "pg_multixact/offsets",
1836  "multixact_member", NUM_MXACTMEMBER_BUFFERS, 0,
1837  MultiXactMemberControlLock, "pg_multixact/members",
1839 
1840  /* Initialize our shared state struct */
1841  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1843  &found);
1844  if (!IsUnderPostmaster)
1845  {
1846  Assert(!found);
1847 
1848  /* Make sure we zero out the per-backend state */
1850  }
1851  else
1852  Assert(found);
1853 
1854  /*
1855  * Set up array pointers. Note that perBackendXactIds[0] is wasted space
1856  * since we only use indexes 1..MaxOldestSlot in each array.
1857  */
1860 }
#define NUM_MXACTMEMBER_BUFFERS
Definition: multixact.h:33
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:3106
#define MemSet(start, val, len)
Definition: c.h:956
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
#define NUM_MXACTOFFSET_BUFFERS
Definition: multixact.h:32
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
#define DEBUG2
Definition: elog.h:24
bool IsUnderPostmaster
Definition: globals.c:109
#define debug_elog2(a, b)
Definition: multixact.c:333
static bool MultiXactMemberPagePrecedes(int page1, int page2)
Definition: multixact.c:3124
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:733
#define MaxOldestSlot
Definition: multixact.c:288
#define MultiXactMemberCtl
Definition: multixact.c:191
#define SHARED_MULTIXACT_STATE_SIZE
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id)
Definition: slru.c:164

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1805 of file multixact.c.

References add_size(), NUM_MXACTMEMBER_BUFFERS, NUM_MXACTOFFSET_BUFFERS, SHARED_MULTIXACT_STATE_SIZE, and SimpleLruShmemSize().

Referenced by CreateSharedMemoryAndSemaphores().

1806 {
1807  Size size;
1808 
1809  /* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
1810 #define SHARED_MULTIXACT_STATE_SIZE \
1811  add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
1812  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1813 
1817 
1818  return size;
1819 }
#define NUM_MXACTMEMBER_BUFFERS
Definition: multixact.h:33
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:144
#define NUM_MXACTOFFSET_BUFFERS
Definition: multixact.h:32
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
size_t Size
Definition: c.h:467
#define SHARED_MULTIXACT_STATE_SIZE

◆ mxid_to_string()

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

Definition at line 1633 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().

1634 {
1635  static char *str = NULL;
1637  int i;
1638 
1639  if (str != NULL)
1640  pfree(str);
1641 
1642  initStringInfo(&buf);
1643 
1644  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1645  mxstatus_to_string(members[0].status));
1646 
1647  for (i = 1; i < nmembers; i++)
1648  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1649  mxstatus_to_string(members[i].status));
1650 
1651  appendStringInfoChar(&buf, ']');
1653  pfree(buf.data);
1654  return str;
1655 }
void pfree(void *pointer)
Definition: mcxt.c:1056
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
static char * buf
Definition: pg_test_fsync.c:67
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:1173
int i
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1610
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1707 of file multixact.c.

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

Referenced by PrepareTransaction().

1708 {
1709  MultiXactId myOldestMember;
1710 
1711  /*
1712  * Transfer our OldestMemberMXactId value to the slot reserved for the
1713  * prepared transaction.
1714  */
1715  myOldestMember = OldestMemberMXactId[MyBackendId];
1716  if (MultiXactIdIsValid(myOldestMember))
1717  {
1718  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1719 
1720  /*
1721  * Even though storing MultiXactId is atomic, acquire lock to make
1722  * sure others see both changes, not just the reset of the slot of the
1723  * current backend. Using a volatile pointer might suffice, but this
1724  * isn't a hot spot.
1725  */
1726  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1727 
1728  OldestMemberMXactId[dummyBackendId] = myOldestMember;
1730 
1731  LWLockRelease(MultiXactGenLock);
1732  }
1733 
1734  /*
1735  * We don't need to transfer OldestVisibleMXactId value, because the
1736  * transaction is not going to be looking at any more multixacts once it's
1737  * prepared.
1738  *
1739  * We assume that storing a MultiXactId is atomic and so we need not take
1740  * MultiXactGenLock to do this.
1741  */
1743 
1744  /*
1745  * Discard the local MultiXactId cache like in AtEOX_MultiXact
1746  */
1747  MXactContext = NULL;
1749  MXactCacheMembers = 0;
1750 }
BackendId MyBackendId
Definition: globals.c:81
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
static int MXactCacheMembers
Definition: multixact.c:323
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:863
int BackendId
Definition: backendid.h:21
#define InvalidMultiXactId
Definition: multixact.h:23
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
TransactionId MultiXactId
Definition: c.h:518
static dlist_head MXactCache
Definition: multixact.c:322
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static MemoryContext MXactContext
Definition: multixact.c:324

◆ 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:1726
#define FirstMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:518
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122

◆ SetMultiXactIdLimit()

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

Definition at line 2196 of file multixact.c.

References Assert, autovacuum_multixact_freeze_max_age, DEBUG1, ereport, errhint(), errmsg(), 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().

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

◆ ShutdownMultiXact()

void ShutdownMultiXact ( void  )

Definition at line 2107 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().

Referenced by ShutdownXLOG().

2108 {
2109  /* Flush dirty MultiXact pages to disk */
2110  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(false);
2113  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(false);
2114 }
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1119
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 1982 of file multixact.c.

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

Referenced by StartupXLOG().

1983 {
1986  int pageno;
1987 
1988  /*
1989  * Initialize offset's idea of the latest page number.
1990  */
1991  pageno = MultiXactIdToOffsetPage(multi);
1992  MultiXactOffsetCtl->shared->latest_page_number = pageno;
1993 
1994  /*
1995  * Initialize member's idea of the latest page number.
1996  */
1997  pageno = MXOffsetToMemberPage(offset);
1998  MultiXactMemberCtl->shared->latest_page_number = pageno;
1999 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:520
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:518
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 2005 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().

2006 {
2007  MultiXactId nextMXact;
2008  MultiXactOffset offset;
2009  MultiXactId oldestMXact;
2010  Oid oldestMXactDB;
2011  int pageno;
2012  int entryno;
2013  int flagsoff;
2014 
2015  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2016  nextMXact = MultiXactState->nextMXact;
2017  offset = MultiXactState->nextOffset;
2018  oldestMXact = MultiXactState->oldestMultiXactId;
2019  oldestMXactDB = MultiXactState->oldestMultiXactDB;
2020  LWLockRelease(MultiXactGenLock);
2021 
2022  /* Clean up offsets state */
2023  LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
2024 
2025  /*
2026  * (Re-)Initialize our idea of the latest page number for offsets.
2027  */
2028  pageno = MultiXactIdToOffsetPage(nextMXact);
2029  MultiXactOffsetCtl->shared->latest_page_number = pageno;
2030 
2031  /*
2032  * Zero out the remainder of the current offsets page. See notes in
2033  * TrimCLOG() for background. Unlike CLOG, some WAL record covers every
2034  * pg_multixact SLRU mutation. Since, also unlike CLOG, we ignore the WAL
2035  * rule "write xlog before data," nextMXact successors may carry obsolete,
2036  * nonzero offset values. Zero those so case 2 of GetMultiXactIdMembers()
2037  * operates normally.
2038  */
2039  entryno = MultiXactIdToOffsetEntry(nextMXact);
2040  if (entryno != 0)
2041  {
2042  int slotno;
2043  MultiXactOffset *offptr;
2044 
2045  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2046  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2047  offptr += entryno;
2048 
2049  MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
2050 
2051  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2052  }
2053 
2054  LWLockRelease(MultiXactOffsetControlLock);
2055 
2056  /* And the same for members */
2057  LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
2058 
2059  /*
2060  * (Re-)Initialize our idea of the latest page number for members.
2061  */
2062  pageno = MXOffsetToMemberPage(offset);
2063  MultiXactMemberCtl->shared->latest_page_number = pageno;
2064 
2065  /*
2066  * Zero out the remainder of the current members page. See notes in
2067  * TrimCLOG() for motivation.
2068  */
2069  flagsoff = MXOffsetToFlagsOffset(offset);
2070  if (flagsoff != 0)
2071  {
2072  int slotno;
2073  TransactionId *xidptr;
2074  int memberoff;
2075 
2076  memberoff = MXOffsetToMemberOffset(offset);
2077  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2078  xidptr = (TransactionId *)
2079  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2080 
2081  MemSet(xidptr, 0, BLCKSZ - memberoff);
2082 
2083  /*
2084  * Note: we don't need to zero out the flag bits in the remaining
2085  * members of the current group, because they are always reset before
2086  * writing.
2087  */
2088 
2089  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2090  }
2091 
2092  LWLockRelease(MultiXactMemberControlLock);
2093 
2094  /* signal that we're officially up */
2095  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2097  LWLockRelease(MultiXactGenLock);
2098 
2099  /* Now compute how far away the next members wraparound is. */
2100  SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2101 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:520
uint32 TransactionId
Definition: c.h:508
MultiXactOffset nextOffset
Definition: multixact.c:206
#define MemSet(start, val, len)
Definition: c.h:956
#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:1726
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:374
#define MultiXactOffsetCtl
Definition: multixact.c:190
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2196
TransactionId MultiXactId
Definition: c.h:518
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2935 of file multixact.c.

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

2936 {
2937  MultiXactId oldestMulti;
2938  MultiXactId nextMulti;
2939  MultiXactOffset newOldestOffset;
2940  MultiXactOffset oldestOffset;
2941  MultiXactOffset nextOffset;
2942  mxtruncinfo trunc;
2943  MultiXactId earliest;
2944 
2947 
2948  /*
2949  * We can only allow one truncation to happen at once. Otherwise parts of
2950  * members might vanish while we're doing lookups or similar. There's no
2951  * need to have an interlock with creating new multis or such, since those
2952  * are constrained by the limits (which only grow, never shrink).
2953  */
2954  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
2955 
2956  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2957  nextMulti = MultiXactState->nextMXact;
2958  nextOffset = MultiXactState->nextOffset;
2959  oldestMulti = MultiXactState->oldestMultiXactId;
2960  LWLockRelease(MultiXactGenLock);
2961  Assert(MultiXactIdIsValid(oldestMulti));
2962 
2963  /*
2964  * Make sure to only attempt truncation if there's values to truncate
2965  * away. In normal processing values shouldn't go backwards, but there's
2966  * some corner cases (due to bugs) where that's possible.
2967  */
2968  if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
2969  {
2970  LWLockRelease(MultiXactTruncationLock);
2971  return;
2972  }
2973 
2974  /*
2975  * Note we can't just plow ahead with the truncation; it's possible that
2976  * there are no segments to truncate, which is a problem because we are
2977  * going to attempt to read the offsets page to determine where to
2978  * truncate the members SLRU. So we first scan the directory to determine
2979  * the earliest offsets page number that we can read without error.
2980  *
2981  * NB: It's also possible that the page that oldestMulti is on has already
2982  * been truncated away, and we crashed before updating oldestMulti.
2983  */
2984  trunc.earliestExistingPage = -1;
2987  if (earliest < FirstMultiXactId)
2988  earliest = FirstMultiXactId;
2989 
2990  /* If there's nothing to remove, we can bail out early. */
2991  if (MultiXactIdPrecedes(oldestMulti, earliest))
2992  {
2993  LWLockRelease(MultiXactTruncationLock);
2994  return;
2995  }
2996 
2997  /*
2998  * First, compute the safe truncation point for MultiXactMember. This is
2999  * the starting offset of the oldest multixact.
3000  *
3001  * Hopefully, find_multixact_start will always work here, because we've
3002  * already checked that it doesn't precede the earliest MultiXact on disk.
3003  * But if it fails, don't truncate anything, and log a message.
3004  */
3005  if (oldestMulti == nextMulti)
3006  {
3007  /* there are NO MultiXacts */
3008  oldestOffset = nextOffset;
3009  }
3010  else if (!find_multixact_start(oldestMulti, &oldestOffset))
3011  {
3012  ereport(LOG,
3013  (errmsg("oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
3014  oldestMulti, earliest)));
3015  LWLockRelease(MultiXactTruncationLock);
3016  return;
3017  }
3018 
3019  /*
3020  * Secondly compute up to where to truncate. Lookup the corresponding
3021  * member offset for newOldestMulti for that.
3022  */
3023  if (newOldestMulti == nextMulti)
3024  {
3025  /* there are NO MultiXacts */
3026  newOldestOffset = nextOffset;
3027  }
3028  else if (!find_multixact_start(newOldestMulti, &newOldestOffset))
3029  {
3030  ereport(LOG,
3031  (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
3032  newOldestMulti)));
3033  LWLockRelease(MultiXactTruncationLock);
3034  return;
3035  }
3036 
3037  elog(DEBUG1, "performing multixact truncation: "
3038  "offsets [%u, %u), offsets segments [%x, %x), "
3039  "members [%u, %u), members segments [%x, %x)",
3040  oldestMulti, newOldestMulti,
3041  MultiXactIdToOffsetSegment(oldestMulti),
3042  MultiXactIdToOffsetSegment(newOldestMulti),
3043  oldestOffset, newOldestOffset,
3044  MXOffsetToMemberSegment(oldestOffset),
3045  MXOffsetToMemberSegment(newOldestOffset));
3046 
3047  /*
3048  * Do truncation, and the WAL logging of the truncation, in a critical
3049  * section. That way offsets/members cannot get out of sync anymore, i.e.
3050  * once consistent the newOldestMulti will always exist in members, even
3051  * if we crashed in the wrong moment.
3052  */
3054 
3055  /*
3056  * Prevent checkpoints from being scheduled concurrently. This is critical
3057  * because otherwise a truncation record might not be replayed after a
3058  * crash/basebackup, even though the state of the data directory would
3059  * require it.
3060  */
3062  MyPgXact->delayChkpt = true;
3063 
3064  /* WAL log truncation */
3065  WriteMTruncateXlogRec(newOldestMultiDB,
3066  oldestMulti, newOldestMulti,
3067  oldestOffset, newOldestOffset);
3068 
3069  /*
3070  * Update in-memory limits before performing the truncation, while inside
3071  * the critical section: Have to do it before truncation, to prevent
3072  * concurrent lookups of those values. Has to be inside the critical
3073  * section as otherwise a future call to this function would error out,
3074  * while looking up the oldest member in offsets, if our caller crashes
3075  * before updating the limits.
3076  */
3077  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
3078  MultiXactState->oldestMultiXactId = newOldestMulti;
3079  MultiXactState->oldestMultiXactDB = newOldestMultiDB;
3080  LWLockRelease(MultiXactGenLock);
3081 
3082  /* First truncate members */
3083  PerformMembersTruncation(oldestOffset, newOldestOffset);
3084 
3085  /* Then offsets */
3086  PerformOffsetsTruncation(oldestMulti, newOldestMulti);
3087 
3088  MyPgXact->delayChkpt = false;
3089 
3090  END_CRIT_SECTION();
3091  LWLockRelease(MultiXactTruncationLock);
3092 }
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:2859
uint32 MultiXactOffset
Definition: c.h:520
MultiXactOffset nextOffset
Definition: multixact.c:206
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition: multixact.c:2721
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
#define LOG
Definition: elog.h:26
bool RecoveryInProgress(void)
Definition: xlog.c:7914
PGXACT * MyPgXact
Definition: proc.c:68
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2882
static void WriteMTruncateXlogRec(Oid oldestMultiDB, MultiXactId startTruncOff, MultiXactId endTruncOff, MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
Definition: multixact.c:3194
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define FirstMultiXactId
Definition: multixact.h:24
#define ereport(elevel, rest)
Definition: elog.h:141
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
bool delayChkpt
Definition: proc.h:235
#define MultiXactOffsetCtl
Definition: multixact.c:190
TransactionId MultiXactId
Definition: c.h:518
#define Assert(condition)
Definition: c.h:733
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1392
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3142
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3156
int earliestExistingPage
Definition: multixact.c:2851
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2910