PostgreSQL Source Code git master
multixact.h File Reference
#include "access/transam.h"
#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 GetMultiXactInfo (uint32 *multixacts, MultiXactOffset *members, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
 
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 (FullTransactionId fxid)
 
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 (FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postcommit (FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postabort (FullTransactionId fxid, 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)
 
char * mxstatus_to_string (MultiXactStatus status)
 

Macro Definition Documentation

◆ FirstMultiXactId

#define FirstMultiXactId   ((MultiXactId) 1)

Definition at line 26 of file multixact.h.

◆ InvalidMultiXactId

#define InvalidMultiXactId   ((MultiXactId) 0)

Definition at line 25 of file multixact.h.

◆ ISUPDATE_from_mxstatus

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

Definition at line 53 of file multixact.h.

◆ MaxMultiXactId

#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)

Definition at line 27 of file multixact.h.

◆ MaxMultiXactOffset

#define MaxMultiXactOffset   ((MultiXactOffset) 0xFFFFFFFF)

Definition at line 31 of file multixact.h.

◆ MaxMultiXactStatus

#define MaxMultiXactStatus   MultiXactStatusUpdate

Definition at line 50 of file multixact.h.

◆ MultiXactIdIsValid

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

Definition at line 29 of file multixact.h.

◆ SizeOfMultiXactCreate

#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Definition at line 82 of file multixact.h.

◆ SizeOfMultiXactTruncate

#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))

Definition at line 97 of file multixact.h.

◆ XLOG_MULTIXACT_CREATE_ID

#define XLOG_MULTIXACT_CREATE_ID   0x20

Definition at line 71 of file multixact.h.

◆ XLOG_MULTIXACT_TRUNCATE_ID

#define XLOG_MULTIXACT_TRUNCATE_ID   0x30

Definition at line 72 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_MEM_PAGE

#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10

Definition at line 70 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_OFF_PAGE

#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00

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

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

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1801 of file multixact.c.

1802{
1803 /*
1804 * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1805 * which should only be valid while within a transaction.
1806 *
1807 * We assume that storing a MultiXactId is atomic and so we need not take
1808 * MultiXactGenLock to do this.
1809 */
1812
1813 /*
1814 * Discard the local MultiXactId cache. Since MXactContext was created as
1815 * a child of TopTransactionContext, we needn't delete it explicitly.
1816 */
1817 MXactContext = NULL;
1819}
ProcNumber MyProcNumber
Definition: globals.c:90
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:361
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:331
static dclist_head MXactCache
Definition: multixact.c:360
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:330
#define InvalidMultiXactId
Definition: multixact.h:25

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

1830{
1832
1833 if (MultiXactIdIsValid(myOldestMember))
1835 &myOldestMember, sizeof(MultiXactId));
1836}
TransactionId MultiXactId
Definition: c.h:670
#define MultiXactIdIsValid(multi)
Definition: multixact.h:29
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1271
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:29

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

Referenced by PrepareTransaction().

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 2026 of file multixact.c.

2027{
2028 /* Zero the initial pages and flush them to disk */
2031}
#define MultiXactMemberCtl
Definition: multixact.c:228
#define MultiXactOffsetCtl
Definition: multixact.c:227
void SimpleLruZeroAndWritePage(SlruCtl ctl, int64 pageno)
Definition: slru.c:444

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruZeroAndWritePage().

Referenced by BootStrapXLOG().

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2243 of file multixact.c.

2244{
2245 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2246
2247 /*
2248 * Write dirty MultiXact pages to disk. This may result in sync requests
2249 * queued for later handling by ProcessSyncRequests(), as part of the
2250 * checkpoint.
2251 */
2254
2255 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2256}
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1347

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ GetMultiXactIdMembers()

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

Definition at line 1339 of file multixact.c.

1341{
1342 int64 pageno;
1343 int64 prev_pageno;
1344 int entryno;
1345 int slotno;
1346 MultiXactOffset *offptr;
1347 MultiXactOffset offset;
1348 int length;
1349 int truelength;
1350 MultiXactId oldestMXact;
1351 MultiXactId nextMXact;
1352 MultiXactMember *ptr;
1353 LWLock *lock;
1354
1355 debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
1356
1357 if (!MultiXactIdIsValid(multi) || from_pgupgrade)
1358 {
1359 *members = NULL;
1360 return -1;
1361 }
1362
1363 /* See if the MultiXactId is in the local cache */
1364 length = mXactCacheGetById(multi, members);
1365 if (length >= 0)
1366 {
1367 debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
1368 mxid_to_string(multi, length, *members));
1369 return length;
1370 }
1371
1372 /* Set our OldestVisibleMXactId[] entry if we didn't already */
1374
1375 /*
1376 * If we know the multi is used only for locking and not for updates, then
1377 * we can skip checking if the value is older than our oldest visible
1378 * multi. It cannot possibly still be running.
1379 */
1380 if (isLockOnly &&
1382 {
1383 debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
1384 *members = NULL;
1385 return -1;
1386 }
1387
1388 /*
1389 * We check known limits on MultiXact before resorting to the SLRU area.
1390 *
1391 * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
1392 * useful; it has already been removed, or will be removed shortly, by
1393 * truncation. If one is passed, an error is raised.
1394 *
1395 * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
1396 * implies undetected ID wraparound has occurred. This raises a hard
1397 * error.
1398 *
1399 * Shared lock is enough here since we aren't modifying any global state.
1400 * Acquire it just long enough to grab the current counter values.
1401 */
1402 LWLockAcquire(MultiXactGenLock, LW_SHARED);
1403
1404 oldestMXact = MultiXactState->oldestMultiXactId;
1405 nextMXact = MultiXactState->nextMXact;
1406
1407 LWLockRelease(MultiXactGenLock);
1408
1409 if (MultiXactIdPrecedes(multi, oldestMXact))
1410 ereport(ERROR,
1411 (errcode(ERRCODE_INTERNAL_ERROR),
1412 errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
1413 multi)));
1414
1415 if (!MultiXactIdPrecedes(multi, nextMXact))
1416 ereport(ERROR,
1417 (errcode(ERRCODE_INTERNAL_ERROR),
1418 errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
1419 multi)));
1420
1421 /*
1422 * Find out the offset at which we need to start reading MultiXactMembers
1423 * and the number of members in the multixact. We determine the latter as
1424 * the difference between this multixact's starting offset and the next
1425 * one's. However, there is one corner case to worry about:
1426 *
1427 * Because GetNewMultiXactId skips over offset zero, to reserve zero for
1428 * to mean "unset", there is an ambiguity near the point of offset
1429 * wraparound. If we see next multixact's offset is one, is that our
1430 * multixact's actual endpoint, or did it end at zero with a subsequent
1431 * increment? We handle this using the knowledge that if the zero'th
1432 * member slot wasn't filled, it'll contain zero, and zero isn't a valid
1433 * transaction ID so it can't be a multixact member. Therefore, if we
1434 * read a zero from the members array, just ignore it.
1435 */
1436 pageno = MultiXactIdToOffsetPage(multi);
1437 entryno = MultiXactIdToOffsetEntry(multi);
1438
1439 /* Acquire the bank lock for the page we need. */
1442
1443 /* read this multi's offset */
1444 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
1445 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1446 offptr += entryno;
1447 offset = *offptr;
1448
1449 Assert(offset != 0);
1450
1451 /* read next multi's offset */
1452 {
1453 MultiXactId tmpMXact;
1454 MultiXactOffset nextMXOffset;
1455
1456 /* handle wraparound if needed */
1457 tmpMXact = multi + 1;
1458 if (tmpMXact < FirstMultiXactId)
1459 tmpMXact = FirstMultiXactId;
1460
1461 prev_pageno = pageno;
1462
1463 pageno = MultiXactIdToOffsetPage(tmpMXact);
1464 entryno = MultiXactIdToOffsetEntry(tmpMXact);
1465
1466 if (pageno != prev_pageno)
1467 {
1468 LWLock *newlock;
1469
1470 /*
1471 * Since we're going to access a different SLRU page, if this page
1472 * falls under a different bank, release the old bank's lock and
1473 * acquire the lock of the new bank.
1474 */
1475 newlock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
1476 if (newlock != lock)
1477 {
1478 LWLockRelease(lock);
1479 LWLockAcquire(newlock, LW_EXCLUSIVE);
1480 lock = newlock;
1481 }
1482 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
1483 }
1484
1485 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1486 offptr += entryno;
1487 nextMXOffset = *offptr;
1488
1489 if (nextMXOffset == 0)
1490 ereport(ERROR,
1492 errmsg("MultiXact %u has invalid next offset",
1493 multi)));
1494
1495 length = nextMXOffset - offset;
1496 }
1497
1498 LWLockRelease(lock);
1499 lock = NULL;
1500
1501 /* read the members */
1502 ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
1503
1504 truelength = 0;
1505 prev_pageno = -1;
1506 for (int i = 0; i < length; i++, offset++)
1507 {
1508 TransactionId *xactptr;
1509 uint32 *flagsptr;
1510 int flagsoff;
1511 int bshift;
1512 int memberoff;
1513
1514 pageno = MXOffsetToMemberPage(offset);
1515 memberoff = MXOffsetToMemberOffset(offset);
1516
1517 if (pageno != prev_pageno)
1518 {
1519 LWLock *newlock;
1520
1521 /*
1522 * Since we're going to access a different SLRU page, if this page
1523 * falls under a different bank, release the old bank's lock and
1524 * acquire the lock of the new bank.
1525 */
1526 newlock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
1527 if (newlock != lock)
1528 {
1529 if (lock)
1530 LWLockRelease(lock);
1531 LWLockAcquire(newlock, LW_EXCLUSIVE);
1532 lock = newlock;
1533 }
1534
1535 slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
1536 prev_pageno = pageno;
1537 }
1538
1539 xactptr = (TransactionId *)
1540 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1541
1542 if (!TransactionIdIsValid(*xactptr))
1543 {
1544 /* Corner case: we must be looking at unused slot zero */
1545 Assert(offset == 0);
1546 continue;
1547 }
1548
1549 flagsoff = MXOffsetToFlagsOffset(offset);
1550 bshift = MXOffsetToFlagsBitShift(offset);
1551 flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1552
1553 ptr[truelength].xid = *xactptr;
1554 ptr[truelength].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
1555 truelength++;
1556 }
1557
1558 LWLockRelease(lock);
1559
1560 /* A multixid with zero members should not happen */
1561 Assert(truelength > 0);
1562
1563 /*
1564 * Copy the result into the local cache.
1565 */
1566 mXactCachePut(multi, truelength, ptr);
1567
1568 debug_elog3(DEBUG2, "GetMembers: no cache for %s",
1569 mxid_to_string(multi, truelength, ptr));
1570 *members = ptr;
1571 return truelength;
1572}
int64_t int64
Definition: c.h:538
uint32 MultiXactOffset
Definition: c.h:672
uint32_t uint32
Definition: c.h:541
uint32 TransactionId
Definition: c.h:660
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define DEBUG2
Definition: elog.h:29
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
Assert(PointerIsAligned(start, uint64))
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_SHARED
Definition: lwlock.h:113
@ LW_EXCLUSIVE
Definition: lwlock.h:112
void * palloc(Size size)
Definition: mcxt.c:1365
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
Definition: multixact.c:1655
static int64 MXOffsetToMemberPage(MultiXactOffset offset)
Definition: multixact.c:168
#define MXACT_MEMBER_XACT_BITMASK
Definition: multixact.c:140
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3274
static void MultiXactIdSetOldestVisible(void)
Definition: multixact.c:714
static int MultiXactIdToOffsetEntry(MultiXactId multi)
Definition: multixact.c:114
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1702
static int MXOffsetToMemberOffset(MultiXactOffset offset)
Definition: multixact.c:201
static int64 MultiXactIdToOffsetPage(MultiXactId multi)
Definition: multixact.c:108
#define debug_elog3(a, b, c)
Definition: multixact.c:371
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1770
static int MXOffsetToFlagsOffset(MultiXactOffset offset)
Definition: multixact.c:181
static MultiXactStateData * MultiXactState
Definition: multixact.c:329
static int MXOffsetToFlagsBitShift(MultiXactOffset offset)
Definition: multixact.c:191
#define debug_elog2(a, b)
Definition: multixact.c:370
#define FirstMultiXactId
Definition: multixact.h:26
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:42
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:527
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:160
Definition: lwlock.h:42
TransactionId xid
Definition: multixact.h:59
MultiXactStatus status
Definition: multixact.h:60
MultiXactId nextMXact
Definition: multixact.c:240
MultiXactId oldestMultiXactId
Definition: multixact.c:253
#define TransactionIdIsValid(xid)
Definition: transam.h:41

References Assert(), DEBUG2, debug_elog2, debug_elog3, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg(), ERROR, FirstMultiXactId, i, if(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactIdSetOldestVisible(), MultiXactIdToOffsetEntry(), MultiXactIdToOffsetPage(), MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, MXACT_MEMBER_XACT_BITMASK, mXactCacheGetById(), mXactCachePut(), mxid_to_string(), MXOffsetToFlagsBitShift(), MXOffsetToFlagsOffset(), MXOffsetToMemberOffset(), MXOffsetToMemberPage(), MyProcNumber, MultiXactStateData::nextMXact, MultiXactStateData::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().

◆ GetMultiXactInfo()

bool GetMultiXactInfo ( uint32 multixacts,
MultiXactOffset members,
MultiXactId oldestMultiXactId,
MultiXactOffset oldestOffset 
)

Definition at line 2876 of file multixact.c.

2878{
2879 MultiXactOffset nextOffset;
2880 MultiXactId nextMultiXactId;
2881 bool oldestOffsetKnown;
2882
2883 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2884 nextOffset = MultiXactState->nextOffset;
2885 *oldestMultiXactId = MultiXactState->oldestMultiXactId;
2886 nextMultiXactId = MultiXactState->nextMXact;
2887 *oldestOffset = MultiXactState->oldestOffset;
2888 oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2889 LWLockRelease(MultiXactGenLock);
2890
2891 if (!oldestOffsetKnown)
2892 {
2893 *members = 0;
2894 *multixacts = 0;
2895 *oldestMultiXactId = InvalidMultiXactId;
2896 *oldestOffset = 0;
2897 return false;
2898 }
2899
2900 *members = nextOffset - *oldestOffset;
2901 *multixacts = nextMultiXactId - *oldestMultiXactId;
2902 return true;
2903}
MultiXactOffset nextOffset
Definition: multixact.c:243
MultiXactOffset oldestOffset
Definition: multixact.c:261

References InvalidMultiXactId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactState, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactId, MultiXactStateData::oldestOffset, and MultiXactStateData::oldestOffsetKnown.

Referenced by MultiXactMemberFreezeThreshold().

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2603 of file multixact.c.

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

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, "%" PRId64, 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:539
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:70
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:69
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:72
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:71
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:76
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:79
MultiXactOffset moff
Definition: multixact.h:77
MultiXactId endTruncOff
Definition: multixact.h:90
MultiXactOffset startTruncMemb
Definition: multixact.h:93
MultiXactOffset endTruncMemb
Definition: multixact.h:94
MultiXactId startTruncOff
Definition: multixact.h:89
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:409
#define XLogRecGetData(decoder)
Definition: xlogreader.h:414

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

3340{
3341 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3342
3343 /* Backup blocks are not used in multixact records */
3345
3346 if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3347 {
3348 int64 pageno;
3349
3350 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3352 }
3353 else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3354 {
3355 int64 pageno;
3356
3357 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3359 }
3360 else if (info == XLOG_MULTIXACT_CREATE_ID)
3361 {
3362 xl_multixact_create *xlrec =
3364 TransactionId max_xid;
3365 int i;
3366
3367 /* Store the data back into the SLRU files */
3368 RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3369 xlrec->members);
3370
3371 /* Make sure nextMXact/nextOffset are beyond what this record has */
3372 MultiXactAdvanceNextMXact(xlrec->mid + 1,
3373 xlrec->moff + xlrec->nmembers);
3374
3375 /*
3376 * Make sure nextXid is beyond any XID mentioned in the record. This
3377 * should be unnecessary, since any XID found here ought to have other
3378 * evidence in the XLOG, but let's be safe.
3379 */
3380 max_xid = XLogRecGetXid(record);
3381 for (i = 0; i < xlrec->nmembers; i++)
3382 {
3383 if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3384 max_xid = xlrec->members[i].xid;
3385 }
3386
3388 }
3389 else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3390 {
3392 int64 pageno;
3393
3394 memcpy(&xlrec, XLogRecGetData(record),
3396
3397 elog(DEBUG1, "replaying multixact truncation: "
3398 "offsets [%u, %u), offsets segments [%" PRIx64 ", %" PRIx64 "), "
3399 "members [%u, %u), members segments [%" PRIx64 ", %" PRIx64 ")",
3400 xlrec.startTruncOff, xlrec.endTruncOff,
3403 xlrec.startTruncMemb, xlrec.endTruncMemb,
3406
3407 /* should not be required, but more than cheap enough */
3408 LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3409
3410 /*
3411 * Advance the horizon values, so they're current at the end of
3412 * recovery.
3413 */
3414 SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3415
3417
3418 /*
3419 * During XLOG replay, latest_page_number isn't necessarily set up
3420 * yet; insert a suitable value to bypass the sanity test in
3421 * SimpleLruTruncate.
3422 */
3423 pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3424 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3425 pageno);
3427
3428 LWLockRelease(MultiXactTruncationLock);
3429 }
3430 else
3431 elog(PANIC, "multixact_redo: unknown op code %u", info);
3432}
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:483
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:226
static int64 MultiXactIdToOffsetSegment(MultiXactId multi)
Definition: multixact.c:120
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:3034
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:3005
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2301
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:900
static int64 MXOffsetToMemberSegment(MultiXactOffset offset)
Definition: multixact.c:174
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2450
#define SizeOfMultiXactTruncate
Definition: multixact.h:97
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.h:263
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:304
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:411
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:416

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

◆ multixact_twophase_postabort()

void multixact_twophase_postabort ( FullTransactionId  fxid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1928 of file multixact.c.

1930{
1931 multixact_twophase_postcommit(fxid, info, recdata, len);
1932}
void multixact_twophase_postcommit(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1913
const void size_t len

References len, and multixact_twophase_postcommit().

◆ multixact_twophase_postcommit()

void multixact_twophase_postcommit ( FullTransactionId  fxid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1913 of file multixact.c.

1915{
1916 ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, true);
1917
1918 Assert(len == sizeof(MultiXactId));
1919
1920 OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1921}
int ProcNumber
Definition: procnumber.h:24
ProcNumber TwoPhaseGetDummyProcNumber(FullTransactionId fxid, bool lock_held)
Definition: twophase.c:908

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

Referenced by multixact_twophase_postabort().

◆ multixact_twophase_recover()

void multixact_twophase_recover ( FullTransactionId  fxid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1892 of file multixact.c.

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

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2450 of file multixact.c.

2452{
2453 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2455 {
2456 debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2457 MultiXactState->nextMXact = minMulti;
2458 }
2460 {
2461 debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2462 minMultiOffset);
2463 MultiXactState->nextOffset = minMultiOffset;
2464 }
2465 LWLockRelease(MultiXactGenLock);
2466}
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3300

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

2476{
2478
2480 SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2481}
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 2221 of file multixact.c.

2226{
2227 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2228 *nextMulti = MultiXactState->nextMXact;
2229 *nextMultiOffset = MultiXactState->nextOffset;
2230 *oldestMulti = MultiXactState->oldestMultiXactId;
2231 *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2232 LWLockRelease(MultiXactGenLock);
2233
2235 "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2236 *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2237}
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:374

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

420{
421 MultiXactId newMulti;
422 MultiXactMember members[2];
423
426
427 Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));
428
429 /* MultiXactIdSetOldestMember() must have been called already. */
431
432 /*
433 * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
434 * are still running. In typical usage, xid2 will be our own XID and the
435 * caller just did a check on xid1, so it'd be wasted effort.
436 */
437
438 members[0].xid = xid1;
439 members[0].status = status1;
440 members[1].xid = xid2;
441 members[1].status = status2;
442
443 newMulti = MultiXactIdCreateFromMembers(2, members);
444
445 debug_elog3(DEBUG2, "Create: %s",
446 mxid_to_string(newMulti, 2, members));
447
448 return newMulti;
449}
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:799
#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 799 of file multixact.c.

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

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

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

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

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

3289{
3290 int32 diff = (int32) (multi1 - multi2);
3291
3292 return (diff <= 0);
3293}

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

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

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

2934{
2935 MultiXactOffset members;
2936 uint32 multixacts;
2937 uint32 victim_multixacts;
2938 double fraction;
2939 int result;
2940 MultiXactId oldestMultiXactId;
2941 MultiXactOffset oldestOffset;
2942
2943 /* If we can't determine member space utilization, assume the worst. */
2944 if (!GetMultiXactInfo(&multixacts, &members, &oldestMultiXactId, &oldestOffset))
2945 return 0;
2946
2947 /* If member space utilization is low, no special action is required. */
2948 if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2950
2951 /*
2952 * Compute a target for relminmxid advancement. The number of multixacts
2953 * we try to eliminate from the system is based on how far we are past
2954 * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2955 */
2956 fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2958 victim_multixacts = multixacts * fraction;
2959
2960 /* fraction could be > 1.0, but lowest possible freeze age is zero */
2961 if (victim_multixacts > multixacts)
2962 return 0;
2963 result = multixacts - victim_multixacts;
2964
2965 /*
2966 * Clamp to autovacuum_multixact_freeze_max_age, so that we never make
2967 * autovacuum less aggressive than it would otherwise be.
2968 */
2970}
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:130
#define Min(x, y)
Definition: c.h:1006
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:211
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:212
bool GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *members, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
Definition: multixact.c:2876

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

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

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3447 of file multixact.c.

3448{
3449 return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3450}
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1856

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3438 of file multixact.c.

3439{
3440 return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3441}

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2267 of file multixact.c.

2269{
2270 debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2271 nextMulti, nextMultiOffset);
2272 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2273 MultiXactState->nextMXact = nextMulti;
2274 MultiXactState->nextOffset = nextMultiOffset;
2275 LWLockRelease(MultiXactGenLock);
2276
2277 /*
2278 * During a binary upgrade, make sure that the offsets SLRU is large
2279 * enough to contain the next value that would be created.
2280 *
2281 * We need to do this pretty early during the first startup in binary
2282 * upgrade mode: before StartupMultiXact() in fact, because this routine
2283 * is called even before that by StartupXLOG(). And we can't do it
2284 * earlier than at this point, because during that first call of this
2285 * routine we determine the MultiXactState->nextMXact value that
2286 * MaybeExtendOffsetSlru needs.
2287 */
2288 if (IsBinaryUpgrade)
2290}
bool IsBinaryUpgrade
Definition: globals.c:121
static void MaybeExtendOffsetSlru(void)
Definition: multixact.c:2049

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

1958{
1959 bool found;
1960
1961 debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1962
1965
1967 "multixact_offset", multixact_offset_buffers, 0,
1968 "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1969 LWTRANCHE_MULTIXACTOFFSET_SLRU,
1971 false);
1974 "multixact_member", multixact_member_buffers, 0,
1975 "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1976 LWTRANCHE_MULTIXACTMEMBER_SLRU,
1978 false);
1979 /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1980
1981 /* Initialize our shared state struct */
1982 MultiXactState = ShmemInitStruct("Shared MultiXact State",
1984 &found);
1985 if (!IsUnderPostmaster)
1986 {
1987 Assert(!found);
1988
1989 /* Make sure we zero out the per-backend state */
1991 }
1992 else
1993 Assert(found);
1994
1995 /*
1996 * Set up array pointers.
1997 */
2000}
#define MemSet(start, val, len)
Definition: c.h:1022
int multixact_offset_buffers
Definition: globals.c:163
bool IsUnderPostmaster
Definition: globals.c:120
int multixact_member_buffers
Definition: globals.c:162
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3254
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:105
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3234
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:389
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:185
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:320
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40

References Assert(), DEBUG2, debug_elog2, IsUnderPostmaster, MaxOldestSlot, MemSet, multixact_member_buffers, multixact_offset_buffers, MULTIXACT_OFFSETS_PER_PAGE, MultiXactMemberCtl, MultiXactMemberPagePrecedes(), MultiXactOffsetCtl, MultiXactOffsetPagePrecedes(), MultiXactState, 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 1940 of file multixact.c.

1941{
1942 Size size;
1943
1944 /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1945#define SHARED_MULTIXACT_STATE_SIZE \
1946 add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1947 mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1948
1952
1953 return size;
1954}
size_t Size
Definition: c.h:613
Size add_size(Size s1, Size s2)
Definition: shmem.c:495
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:198

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

Referenced by CalculateShmemSize().

◆ mxid_to_string()

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

Definition at line 1770 of file multixact.c.

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

◆ mxstatus_to_string()

char * mxstatus_to_string ( MultiXactStatus  status)

Definition at line 1747 of file multixact.c.

1748{
1749 switch (status)
1750 {
1752 return "keysh";
1754 return "sh";
1756 return "fornokeyupd";
1758 return "forupd";
1760 return "nokeyupd";
1762 return "upd";
1763 default:
1764 elog(ERROR, "unrecognized multixact status %d", status);
1765 return "";
1766 }
1767}

References elog, ERROR, MultiXactStatusForKeyShare, MultiXactStatusForNoKeyUpdate, MultiXactStatusForShare, MultiXactStatusForUpdate, MultiXactStatusNoKeyUpdate, and MultiXactStatusUpdate.

Referenced by MultiXactIdExpand(), mxid_to_string(), and pg_get_multixact_members().

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( FullTransactionId  fxid)

Definition at line 1843 of file multixact.c.

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

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

776{
777 LWLockAcquire(MultiXactGenLock, LW_SHARED);
780 LWLockRelease(MultiXactGenLock);
781
782 if (*oldest < FirstMultiXactId)
783 *oldest = FirstMultiXactId;
784 if (*next < FirstMultiXactId)
786}
static int32 next
Definition: blutils.c:224

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

756{
757 MultiXactId mxid;
758
759 /* XXX we could presumably do this without a lock. */
760 LWLockAcquire(MultiXactGenLock, LW_SHARED);
762 LWLockRelease(MultiXactGenLock);
763
764 if (mxid < FirstMultiXactId)
765 mxid = FirstMultiXactId;
766
767 return mxid;
768}

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

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

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

2085{
2088 int64 pageno;
2089
2090 /*
2091 * Initialize offset's idea of the latest page number.
2092 */
2093 pageno = MultiXactIdToOffsetPage(multi);
2094 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2095 pageno);
2096
2097 /*
2098 * Initialize member's idea of the latest page number.
2099 */
2100 pageno = MXOffsetToMemberPage(offset);
2101 pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2102 pageno);
2103}

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

2110{
2111 MultiXactId nextMXact;
2112 MultiXactOffset offset;
2113 MultiXactId oldestMXact;
2114 Oid oldestMXactDB;
2115 int64 pageno;
2116 int entryno;
2117 int flagsoff;
2118
2119 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2120 nextMXact = MultiXactState->nextMXact;
2121 offset = MultiXactState->nextOffset;
2122 oldestMXact = MultiXactState->oldestMultiXactId;
2123 oldestMXactDB = MultiXactState->oldestMultiXactDB;
2124 LWLockRelease(MultiXactGenLock);
2125
2126 /* Clean up offsets state */
2127
2128 /*
2129 * (Re-)Initialize our idea of the latest page number for offsets.
2130 */
2131 pageno = MultiXactIdToOffsetPage(nextMXact);
2132 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2133 pageno);
2134
2135 /*
2136 * Set the offset of nextMXact on the offsets page. This is normally done
2137 * in RecordNewMultiXact() of the previous multixact, but let's be sure
2138 * the next page exists, if the nextMXact was reset with pg_resetwal for
2139 * example.
2140 *
2141 * Zero out the remainder of the page. See notes in TrimCLOG() for
2142 * background. Unlike CLOG, some WAL record covers every pg_multixact
2143 * SLRU mutation. Since, also unlike CLOG, we ignore the WAL rule "write
2144 * xlog before data," nextMXact successors may carry obsolete, nonzero
2145 * offset values.
2146 */
2147 entryno = MultiXactIdToOffsetEntry(nextMXact);
2148 {
2149 int slotno;
2150 MultiXactOffset *offptr;
2152
2154 if (entryno == 0)
2155 slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
2156 else
2157 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2158 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2159 offptr += entryno;
2160
2161 *offptr = offset;
2162 if (entryno != 0 && (entryno + 1) * sizeof(MultiXactOffset) != BLCKSZ)
2163 MemSet(offptr + 1, 0, BLCKSZ - (entryno + 1) * sizeof(MultiXactOffset));
2164
2165 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2166 LWLockRelease(lock);
2167 }
2168
2169 /*
2170 * And the same for members.
2171 *
2172 * (Re-)Initialize our idea of the latest page number for members.
2173 */
2174 pageno = MXOffsetToMemberPage(offset);
2175 pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2176 pageno);
2177
2178 /*
2179 * Zero out the remainder of the current members page. See notes in
2180 * TrimCLOG() for motivation.
2181 */
2182 flagsoff = MXOffsetToFlagsOffset(offset);
2183 if (flagsoff != 0)
2184 {
2185 int slotno;
2186 TransactionId *xidptr;
2187 int memberoff;
2189
2191 memberoff = MXOffsetToMemberOffset(offset);
2192 slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2193 xidptr = (TransactionId *)
2194 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2195
2196 MemSet(xidptr, 0, BLCKSZ - memberoff);
2197
2198 /*
2199 * Note: we don't need to zero out the flag bits in the remaining
2200 * members of the current group, because they are always reset before
2201 * writing.
2202 */
2203
2204 MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2205 LWLockRelease(lock);
2206 }
2207
2208 /* signal that we're officially up */
2209 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2211 LWLockRelease(MultiXactGenLock);
2212
2213 /* Now compute how far away the next members wraparound is. */
2214 SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2215}
unsigned int Oid
Definition: postgres_ext.h:32
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:375

References MultiXactStateData::finishedStartup, if(), 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(), SimpleLruReadPage(), and SimpleLruZeroPage().

Referenced by StartupXLOG().

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  newOldestMulti,
Oid  newOldestMultiDB 
)

Definition at line 3059 of file multixact.c.

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

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