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

Go to the source code of this file.

Data Structures

struct  MultiXactMember
 
struct  xl_multixact_create
 
struct  xl_multixact_truncate
 

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Macro Definition Documentation

◆ FirstMultiXactId

#define FirstMultiXactId   ((MultiXactId) 1)

Definition at line 25 of file multixact.h.

◆ InvalidMultiXactId

#define InvalidMultiXactId   ((MultiXactId) 0)

Definition at line 24 of file multixact.h.

◆ ISUPDATE_from_mxstatus

#define ISUPDATE_from_mxstatus (   status)     ((status) > MultiXactStatusForUpdate)

Definition at line 52 of file multixact.h.

◆ MaxMultiXactId

#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)

Definition at line 26 of file multixact.h.

◆ MaxMultiXactOffset

#define MaxMultiXactOffset   ((MultiXactOffset) 0xFFFFFFFF)

Definition at line 30 of file multixact.h.

◆ MaxMultiXactStatus

#define MaxMultiXactStatus   MultiXactStatusUpdate

Definition at line 49 of file multixact.h.

◆ MultiXactIdIsValid

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

Definition at line 28 of file multixact.h.

◆ SizeOfMultiXactCreate

#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Definition at line 81 of file multixact.h.

◆ SizeOfMultiXactTruncate

#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))

Definition at line 96 of file multixact.h.

◆ XLOG_MULTIXACT_CREATE_ID

#define XLOG_MULTIXACT_CREATE_ID   0x20

Definition at line 70 of file multixact.h.

◆ XLOG_MULTIXACT_TRUNCATE_ID

#define XLOG_MULTIXACT_TRUNCATE_ID   0x30

Definition at line 71 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_MEM_PAGE

#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10

Definition at line 69 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_OFF_PAGE

#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00

Definition at line 68 of file multixact.h.

Typedef Documentation

◆ MultiXactMember

◆ xl_multixact_create

◆ xl_multixact_truncate

Enumeration Type Documentation

◆ MultiXactStatus

Enumerator
MultiXactStatusForKeyShare 
MultiXactStatusForShare 
MultiXactStatusForNoKeyUpdate 
MultiXactStatusForUpdate 
MultiXactStatusNoKeyUpdate 
MultiXactStatusUpdate 

Definition at line 37 of file multixact.h.

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

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1808 of file multixact.c.

1809{
1810 /*
1811 * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1812 * which should only be valid while within a transaction.
1813 *
1814 * We assume that storing a MultiXactId is atomic and so we need not take
1815 * MultiXactGenLock to do this.
1816 */
1819
1820 /*
1821 * Discard the local MultiXactId cache. Since MXactContext was created as
1822 * a child of TopTransactionContext, we needn't delete it explicitly.
1823 */
1824 MXactContext = NULL;
1826}
ProcNumber MyProcNumber
Definition: globals.c:89
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:372
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:342
static dclist_head MXactCache
Definition: multixact.c:371
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:341
#define InvalidMultiXactId
Definition: multixact.h:24

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

Referenced by AbortTransaction(), CommitTransaction(), and test_read_multixact().

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1836 of file multixact.c.

1837{
1839
1840 if (MultiXactIdIsValid(myOldestMember))
1842 &myOldestMember, sizeof(MultiXactId));
1843}
TransactionId MultiXactId
Definition: c.h:619
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1264
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27

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

Referenced by PrepareTransaction().

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 2034 of file multixact.c.

2035{
2036 int slotno;
2037 LWLock *lock;
2038
2041
2042 /* Create and zero the first page of the offsets log */
2043 slotno = ZeroMultiXactOffsetPage(0, false);
2044
2045 /* Make sure it's written out */
2047 Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
2048
2049 LWLockRelease(lock);
2050
2053
2054 /* Create and zero the first page of the members log */
2055 slotno = ZeroMultiXactMemberPage(0, false);
2056
2057 /* Make sure it's written out */
2059 Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
2060
2061 LWLockRelease(lock);
2062}
#define Assert(condition)
Definition: c.h:815
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2090
#define MultiXactMemberCtl
Definition: multixact.c:233
#define MultiXactOffsetCtl
Definition: multixact.c:232
static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2074
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:732
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:175
Definition: lwlock.h:42

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

Referenced by BootStrapXLOG().

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2304 of file multixact.c.

2305{
2306 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2307
2308 /*
2309 * Write dirty MultiXact pages to disk. This may result in sync requests
2310 * queued for later handling by ProcessSyncRequests(), as part of the
2311 * checkpoint.
2312 */
2315
2316 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2317}
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1322

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ GetMultiXactIdMembers()

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

Definition at line 1299 of file multixact.c.

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

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

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

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2660 of file multixact.c.

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

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

Referenced by heapam_relation_set_new_filelocator(), vac_update_datfrozenxid(), and vacuum_get_cutoffs().

◆ multixact_desc()

void multixact_desc ( StringInfo  buf,
XLogReaderState record 
)

Definition at line 50 of file mxactdesc.c.

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

References appendStringInfo(), buf, xl_multixact_truncate::endTruncMemb, xl_multixact_truncate::endTruncOff, i, xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, xl_multixact_create::nmembers, out_member(), xl_multixact_truncate::startTruncMemb, xl_multixact_truncate::startTruncOff, XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_TRUNCATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, XLogRecGetData, and XLogRecGetInfo.

◆ multixact_identify()

const char * multixact_identify ( uint8  info)

Definition at line 84 of file mxactdesc.c.

85{
86 const char *id = NULL;
87
88 switch (info & ~XLR_INFO_MASK)
89 {
91 id = "ZERO_OFF_PAGE";
92 break;
94 id = "ZERO_MEM_PAGE";
95 break;
97 id = "CREATE_ID";
98 break;
100 id = "TRUNCATE_ID";
101 break;
102 }
103
104 return id;
105}
#define XLR_INFO_MASK
Definition: xlogrecord.h:62

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

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 3394 of file multixact.c.

3395{
3396 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3397
3398 /* Backup blocks are not used in multixact records */
3400
3401 if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3402 {
3403 int64 pageno;
3404 int slotno;
3405 LWLock *lock;
3406
3407 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3408
3411
3412 slotno = ZeroMultiXactOffsetPage(pageno, false);
3414 Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3415
3416 LWLockRelease(lock);
3417 }
3418 else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3419 {
3420 int64 pageno;
3421 int slotno;
3422 LWLock *lock;
3423
3424 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3425
3428
3429 slotno = ZeroMultiXactMemberPage(pageno, false);
3431 Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3432
3433 LWLockRelease(lock);
3434 }
3435 else if (info == XLOG_MULTIXACT_CREATE_ID)
3436 {
3437 xl_multixact_create *xlrec =
3439 TransactionId max_xid;
3440 int i;
3441
3442 /* Store the data back into the SLRU files */
3443 RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3444 xlrec->members);
3445
3446 /* Make sure nextMXact/nextOffset are beyond what this record has */
3447 MultiXactAdvanceNextMXact(xlrec->mid + 1,
3448 xlrec->moff + xlrec->nmembers);
3449
3450 /*
3451 * Make sure nextXid is beyond any XID mentioned in the record. This
3452 * should be unnecessary, since any XID found here ought to have other
3453 * evidence in the XLOG, but let's be safe.
3454 */
3455 max_xid = XLogRecGetXid(record);
3456 for (i = 0; i < xlrec->nmembers; i++)
3457 {
3458 if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3459 max_xid = xlrec->members[i].xid;
3460 }
3461
3463 }
3464 else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3465 {
3467 int64 pageno;
3468
3469 memcpy(&xlrec, XLogRecGetData(record),
3471
3472 elog(DEBUG1, "replaying multixact truncation: "
3473 "offsets [%u, %u), offsets segments [%llx, %llx), "
3474 "members [%u, %u), members segments [%llx, %llx)",
3475 xlrec.startTruncOff, xlrec.endTruncOff,
3476 (unsigned long long) MultiXactIdToOffsetSegment(xlrec.startTruncOff),
3477 (unsigned long long) MultiXactIdToOffsetSegment(xlrec.endTruncOff),
3478 xlrec.startTruncMemb, xlrec.endTruncMemb,
3479 (unsigned long long) MXOffsetToMemberSegment(xlrec.startTruncMemb),
3480 (unsigned long long) MXOffsetToMemberSegment(xlrec.endTruncMemb));
3481
3482 /* should not be required, but more than cheap enough */
3483 LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3484
3485 /*
3486 * Advance the horizon values, so they're current at the end of
3487 * recovery.
3488 */
3489 SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3490
3492
3493 /*
3494 * During XLOG replay, latest_page_number isn't necessarily set up
3495 * yet; insert a suitable value to bypass the sanity test in
3496 * SimpleLruTruncate.
3497 */
3498 pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3499 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3500 pageno);
3502
3503 LWLockRelease(MultiXactTruncationLock);
3504 }
3505 else
3506 elog(PANIC, "multixact_redo: unknown op code %u", info);
3507}
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:485
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:225
static int64 MultiXactIdToOffsetSegment(MultiXactId multi)
Definition: multixact.c:125
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:3077
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:3048
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2362
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:916
static int64 MXOffsetToMemberSegment(MultiXactOffset offset)
Definition: multixact.c:179
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2511
#define SizeOfMultiXactTruncate
Definition: multixact.h:96
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:304
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:412
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:417

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

◆ multixact_twophase_postabort()

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

Definition at line 1935 of file multixact.c.

1937{
1938 multixact_twophase_postcommit(xid, info, recdata, len);
1939}
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1920
const void size_t len

References len, and multixact_twophase_postcommit().

◆ multixact_twophase_postcommit()

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

Definition at line 1920 of file multixact.c.

1922{
1923 ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, true);
1924
1925 Assert(len == sizeof(MultiXactId));
1926
1927 OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1928}
int ProcNumber
Definition: procnumber.h:24
ProcNumber TwoPhaseGetDummyProcNumber(TransactionId xid, bool lock_held)
Definition: twophase.c:903

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

Referenced by multixact_twophase_postabort().

◆ multixact_twophase_recover()

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

Definition at line 1899 of file multixact.c.

1901{
1902 ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1903 MultiXactId oldestMember;
1904
1905 /*
1906 * Get the oldest member XID from the state file record, and set it in the
1907 * OldestMemberMXactId slot reserved for this prepared transaction.
1908 */
1909 Assert(len == sizeof(MultiXactId));
1910 oldestMember = *((MultiXactId *) recdata);
1911
1912 OldestMemberMXactId[dummyProcNumber] = oldestMember;
1913}

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2511 of file multixact.c.

2513{
2514 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2516 {
2517 debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2518 MultiXactState->nextMXact = minMulti;
2519 }
2521 {
2522 debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2523 minMultiOffset);
2524 MultiXactState->nextOffset = minMultiOffset;
2525 }
2526 LWLockRelease(MultiXactGenLock);
2527}
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3343

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

Referenced by multixact_redo(), and xlog_redo().

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2536 of file multixact.c.

2537{
2539
2541 SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2542}
bool InRecovery
Definition: xlogutils.c:50

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

Referenced by xlog_redo().

◆ MultiXactGetCheckptMulti()

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

Definition at line 2282 of file multixact.c.

2287{
2288 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2289 *nextMulti = MultiXactState->nextMXact;
2290 *nextMultiOffset = MultiXactState->nextOffset;
2291 *oldestMulti = MultiXactState->oldestMultiXactId;
2292 *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2293 LWLockRelease(MultiXactGenLock);
2294
2296 "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2297 *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2298}
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:385

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

Referenced by CreateCheckPoint().

◆ MultiXactIdCreate()

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

Definition at line 434 of file multixact.c.

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

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

Referenced by compute_new_xmax_infomask(), and test_create_multixact().

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 815 of file multixact.c.

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

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

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

◆ MultiXactIdExpand()

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

Definition at line 487 of file multixact.c.

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

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

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdIsRunning()

bool MultiXactIdIsRunning ( MultiXactId  multi,
bool  isLockOnly 
)

Definition at line 599 of file multixact.c.

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

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

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

◆ MultiXactIdPrecedes()

◆ MultiXactIdPrecedesOrEquals()

bool MultiXactIdPrecedesOrEquals ( MultiXactId  multi1,
MultiXactId  multi2 
)

Definition at line 3331 of file multixact.c.

3332{
3333 int32 diff = (int32) (multi1 - multi2);
3334
3335 return (diff <= 0);
3336}

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

◆ MultiXactIdSetOldestMember()

void MultiXactIdSetOldestMember ( void  )

Definition at line 673 of file multixact.c.

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

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

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

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2978 of file multixact.c.

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

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

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

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3584 of file multixact.c.

3585{
3586 return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3587}
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1831

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3575 of file multixact.c.

3576{
3577 return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3578}

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2328 of file multixact.c.

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

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

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

◆ MultiXactShmemInit()

void MultiXactShmemInit ( void  )

Definition at line 1964 of file multixact.c.

1965{
1966 bool found;
1967
1968 debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1969
1972
1974 "multixact_offset", multixact_offset_buffers, 0,
1975 "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1978 false);
1981 "multixact_member", multixact_member_buffers, 0,
1982 "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1985 false);
1986 /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1987
1988 /* Initialize our shared state struct */
1989 MultiXactState = ShmemInitStruct("Shared MultiXact State",
1991 &found);
1992 if (!IsUnderPostmaster)
1993 {
1994 Assert(!found);
1995
1996 /* Make sure we zero out the per-backend state */
1999 }
2000 else
2001 Assert(found);
2002
2003 /*
2004 * Set up array pointers.
2005 */
2008}
#define MemSet(start, val, len)
Definition: c.h:977
void ConditionVariableInit(ConditionVariable *cv)
int multixact_offset_buffers
Definition: globals.c:162
bool IsUnderPostmaster
Definition: globals.c:119
int multixact_member_buffers
Definition: globals.c:161
@ LWTRANCHE_MULTIXACTOFFSET_SLRU
Definition: lwlock.h:212
@ LWTRANCHE_MULTIXACTMEMBER_SLRU
Definition: lwlock.h:211
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:183
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:182
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3297
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:110
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3277
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:382
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition: slru.c:252
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:199
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:331
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40

References Assert, ConditionVariableInit(), DEBUG2, debug_elog2, IsUnderPostmaster, LWTRANCHE_MULTIXACTMEMBER_BUFFER, LWTRANCHE_MULTIXACTMEMBER_SLRU, LWTRANCHE_MULTIXACTOFFSET_BUFFER, LWTRANCHE_MULTIXACTOFFSET_SLRU, MaxOldestSlot, MemSet, multixact_member_buffers, multixact_offset_buffers, MULTIXACT_OFFSETS_PER_PAGE, MultiXactMemberCtl, MultiXactMemberPagePrecedes(), MultiXactOffsetCtl, MultiXactOffsetPagePrecedes(), MultiXactState, MultiXactStateData::nextoff_cv, OldestMemberMXactId, OldestVisibleMXactId, MultiXactStateData::perBackendXactIds, SHARED_MULTIXACT_STATE_SIZE, ShmemInitStruct(), SimpleLruInit(), SlruPagePrecedesUnitTests, SYNC_HANDLER_MULTIXACT_MEMBER, and SYNC_HANDLER_MULTIXACT_OFFSET.

Referenced by CreateOrAttachShmemStructs().

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1947 of file multixact.c.

1948{
1949 Size size;
1950
1951 /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1952#define SHARED_MULTIXACT_STATE_SIZE \
1953 add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1954 mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1955
1959
1960 return size;
1961}
size_t Size
Definition: c.h:562
Size add_size(Size s1, Size s2)
Definition: shmem.c:488
static pg_noinline void Size size
Definition: slab.c:607
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:199

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

Referenced by CalculateShmemSize().

◆ mxid_to_string()

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

Definition at line 1777 of file multixact.c.

1778{
1779 static char *str = NULL;
1781 int i;
1782
1783 if (str != NULL)
1784 pfree(str);
1785
1787
1788 appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1789 mxstatus_to_string(members[0].status));
1790
1791 for (i = 1; i < nmembers; i++)
1792 appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1793 mxstatus_to_string(members[i].status));
1794
1797 pfree(buf.data);
1798 return str;
1799}
const char * str
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97

References appendStringInfo(), appendStringInfoChar(), buf, i, initStringInfo(), MemoryContextStrdup(), mxstatus_to_string(), pfree(), str, and TopMemoryContext.

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

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1850 of file multixact.c.

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

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

Referenced by PrepareTransaction().

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 791 of file multixact.c.

792{
793 LWLockAcquire(MultiXactGenLock, LW_SHARED);
796 LWLockRelease(MultiXactGenLock);
797
798 if (*oldest < FirstMultiXactId)
799 *oldest = FirstMultiXactId;
800 if (*next < FirstMultiXactId)
802}
static int32 next
Definition: blutils.c:221

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

Referenced by update_cached_mxid_range().

◆ ReadNextMultiXactId()

MultiXactId ReadNextMultiXactId ( void  )

Definition at line 771 of file multixact.c.

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

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

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

◆ SetMultiXactIdLimit()

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

Definition at line 2362 of file multixact.c.

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

References Assert, autovacuum_multixact_freeze_max_age, DEBUG1, ereport, errhint(), errmsg_internal(), errmsg_plural(), MultiXactStateData::finishedStartup, FirstMultiXactId, get_database_name(), InRecovery, IsTransactionState(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxMultiXactId, MultiXactStateData::multiStopLimit, MultiXactStateData::multiVacLimit, MultiXactStateData::multiWarnLimit, MultiXactStateData::multiWrapLimit, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactState, MultiXactStateData::nextMXact, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, PMSIGNAL_START_AUTOVAC_LAUNCHER, SendPostmasterSignal(), SetOffsetVacuumLimit(), and WARNING.

Referenced by BootStrapXLOG(), multixact_redo(), MultiXactAdvanceOldest(), StartupXLOG(), TrimMultiXact(), and vac_truncate_clog().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2153 of file multixact.c.

2154{
2157 int64 pageno;
2158
2159 /*
2160 * Initialize offset's idea of the latest page number.
2161 */
2162 pageno = MultiXactIdToOffsetPage(multi);
2163 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2164 pageno);
2165
2166 /*
2167 * Initialize member's idea of the latest page number.
2168 */
2169 pageno = MXOffsetToMemberPage(offset);
2170 pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2171 pageno);
2172}

References MultiXactIdToOffsetPage(), MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, MXOffsetToMemberPage(), MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, and pg_atomic_write_u64().

Referenced by StartupXLOG().

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 2178 of file multixact.c.

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

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

Referenced by StartupXLOG().

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  newOldestMulti,
Oid  newOldestMultiDB 
)

Definition at line 3102 of file multixact.c.

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

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

Referenced by vac_truncate_clog().