Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
multixact.c File Reference
#include "postgres.h"
#include "access/multixact.h"
#include "access/slru.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/condition_variable.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/guc_hooks.h"
#include "utils/injection_point.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
Include dependency graph for multixact.c:

Go to the source code of this file.

Data Structures

struct  MultiXactStateData
 
struct  mXactCacheEnt
 
struct  mxtruncinfo
 

Macros

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))
 
#define MXACT_MEMBER_BITS_PER_XACT   8
 
#define MXACT_MEMBER_FLAGS_PER_BYTE   1
 
#define MXACT_MEMBER_XACT_BITMASK   ((1 << MXACT_MEMBER_BITS_PER_XACT) - 1)
 
#define MULTIXACT_FLAGBYTES_PER_GROUP   4
 
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP    (MULTIXACT_FLAGBYTES_PER_GROUP * MXACT_MEMBER_FLAGS_PER_BYTE)
 
#define MULTIXACT_MEMBERGROUP_SIZE    (sizeof(TransactionId) * MULTIXACT_MEMBERS_PER_MEMBERGROUP + MULTIXACT_FLAGBYTES_PER_GROUP)
 
#define MULTIXACT_MEMBERGROUPS_PER_PAGE   (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)
 
#define MULTIXACT_MEMBERS_PER_PAGE    (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)
 
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE    ((uint32) ((0xFFFFFFFF % MULTIXACT_MEMBERS_PER_PAGE) + 1))
 
#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)
 
#define MULTIXACT_MEMBER_DANGER_THRESHOLD    (MaxMultiXactOffset - MaxMultiXactOffset / 4)
 
#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)
 
#define MultiXactMemberCtl   (&MultiXactMemberCtlData)
 
#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)
 
#define MAX_CACHE_ENTRIES   256
 
#define debug_elog2(a, b)
 
#define debug_elog3(a, b, c)
 
#define debug_elog4(a, b, c, d)
 
#define debug_elog5(a, b, c, d, e)
 
#define debug_elog6(a, b, c, d, e, f)
 
#define OFFSET_WARN_SEGMENTS   20
 
#define SHARED_MULTIXACT_STATE_SIZE
 

Typedefs

typedef struct MultiXactStateData MultiXactStateData
 
typedef struct mXactCacheEnt mXactCacheEnt
 
typedef struct mxtruncinfo mxtruncinfo
 

Functions

static int64 MultiXactIdToOffsetPage (MultiXactId multi)
 
static int MultiXactIdToOffsetEntry (MultiXactId multi)
 
static int64 MultiXactIdToOffsetSegment (MultiXactId multi)
 
static int64 MXOffsetToMemberPage (MultiXactOffset offset)
 
static int64 MXOffsetToMemberSegment (MultiXactOffset offset)
 
static int MXOffsetToFlagsOffset (MultiXactOffset offset)
 
static int MXOffsetToFlagsBitShift (MultiXactOffset offset)
 
static int MXOffsetToMemberOffset (MultiXactOffset offset)
 
static MultiXactId PreviousMultiXactId (MultiXactId multi)
 
static void MultiXactIdSetOldestVisible (void)
 
static void RecordNewMultiXact (MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
 
static MultiXactId GetNewMultiXactId (int nmembers, MultiXactOffset *offset)
 
static int mxactMemberComparator (const void *arg1, const void *arg2)
 
static MultiXactId mXactCacheGetBySet (int nmembers, MultiXactMember *members)
 
static int mXactCacheGetById (MultiXactId multi, MultiXactMember **members)
 
static void mXactCachePut (MultiXactId multi, int nmembers, MultiXactMember *members)
 
static bool MultiXactOffsetPagePrecedes (int64 page1, int64 page2)
 
static bool MultiXactMemberPagePrecedes (int64 page1, int64 page2)
 
static bool MultiXactOffsetPrecedes (MultiXactOffset offset1, MultiXactOffset offset2)
 
static void ExtendMultiXactOffset (MultiXactId multi)
 
static void ExtendMultiXactMember (MultiXactOffset offset, int nmembers)
 
static bool MultiXactOffsetWouldWrap (MultiXactOffset boundary, MultiXactOffset start, uint32 distance)
 
static bool SetOffsetVacuumLimit (bool is_startup)
 
static bool find_multixact_start (MultiXactId multi, MultiXactOffset *result)
 
static void WriteMTruncateXlogRec (Oid oldestMultiDB, MultiXactId startTruncOff, MultiXactId endTruncOff, MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
 
MultiXactId MultiXactIdCreate (TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
 
MultiXactId MultiXactIdExpand (MultiXactId multi, TransactionId xid, MultiXactStatus status)
 
bool MultiXactIdIsRunning (MultiXactId multi, bool isLockOnly)
 
void MultiXactIdSetOldestMember (void)
 
MultiXactId ReadNextMultiXactId (void)
 
void ReadMultiXactIdRange (MultiXactId *oldest, MultiXactId *next)
 
MultiXactId MultiXactIdCreateFromMembers (int nmembers, MultiXactMember *members)
 
int GetMultiXactIdMembers (MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
 
char * mxstatus_to_string (MultiXactStatus status)
 
char * mxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)
 
void AtEOXact_MultiXact (void)
 
void AtPrepare_MultiXact (void)
 
void PostPrepare_MultiXact (FullTransactionId fxid)
 
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)
 
Size MultiXactShmemSize (void)
 
void MultiXactShmemInit (void)
 
bool check_multixact_offset_buffers (int *newval, void **extra, GucSource source)
 
bool check_multixact_member_buffers (int *newval, void **extra, GucSource source)
 
void BootStrapMultiXact (void)
 
static void MaybeExtendOffsetSlru (void)
 
void StartupMultiXact (void)
 
void TrimMultiXact (void)
 
void MultiXactGetCheckptMulti (bool is_shutdown, MultiXactId *nextMulti, MultiXactOffset *nextMultiOffset, MultiXactId *oldestMulti, Oid *oldestMultiDB)
 
void CheckPointMultiXact (void)
 
void MultiXactSetNextMXact (MultiXactId nextMulti, MultiXactOffset nextMultiOffset)
 
void SetMultiXactIdLimit (MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
 
void MultiXactAdvanceNextMXact (MultiXactId minMulti, MultiXactOffset minMultiOffset)
 
void MultiXactAdvanceOldest (MultiXactId oldestMulti, Oid oldestMultiDB)
 
MultiXactId GetOldestMultiXactId (void)
 
bool GetMultiXactInfo (uint32 *multixacts, MultiXactOffset *members, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
 
int MultiXactMemberFreezeThreshold (void)
 
static bool SlruScanDirCbFindEarliest (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
static void PerformMembersTruncation (MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
 
static void PerformOffsetsTruncation (MultiXactId oldestMulti, MultiXactId newOldestMulti)
 
void TruncateMultiXact (MultiXactId newOldestMulti, Oid newOldestMultiDB)
 
bool MultiXactIdPrecedes (MultiXactId multi1, MultiXactId multi2)
 
bool MultiXactIdPrecedesOrEquals (MultiXactId multi1, MultiXactId multi2)
 
void multixact_redo (XLogReaderState *record)
 
int multixactoffsetssyncfiletag (const FileTag *ftag, char *path)
 
int multixactmemberssyncfiletag (const FileTag *ftag, char *path)
 

Variables

static SlruCtlData MultiXactOffsetCtlData
 
static SlruCtlData MultiXactMemberCtlData
 
static MultiXactStateDataMultiXactState
 
static MultiXactIdOldestMemberMXactId
 
static MultiXactIdOldestVisibleMXactId
 
static dclist_head MXactCache = DCLIST_STATIC_INIT(MXactCache)
 
static MemoryContext MXactContext = NULL
 

Macro Definition Documentation

◆ debug_elog2

#define debug_elog2 (   a,
  b 
)

Definition at line 377 of file multixact.c.

◆ debug_elog3

#define debug_elog3 (   a,
  b,
  c 
)

Definition at line 378 of file multixact.c.

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

Definition at line 379 of file multixact.c.

◆ debug_elog5

#define debug_elog5 (   a,
  b,
  c,
  d,
  e 
)

Definition at line 380 of file multixact.c.

◆ debug_elog6

#define debug_elog6 (   a,
  b,
  c,
  d,
  e,
 
)

Definition at line 381 of file multixact.c.

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

Definition at line 366 of file multixact.c.

◆ MAX_MEMBERS_IN_LAST_MEMBERS_PAGE

#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE    ((uint32) ((0xFFFFFFFF % MULTIXACT_MEMBERS_PER_PAGE) + 1))

Definition at line 164 of file multixact.c.

◆ MaxOldestSlot

#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)

Definition at line 333 of file multixact.c.

◆ MULTIXACT_FLAGBYTES_PER_GROUP

#define MULTIXACT_FLAGBYTES_PER_GROUP   4

Definition at line 144 of file multixact.c.

◆ MULTIXACT_MEMBER_DANGER_THRESHOLD

#define MULTIXACT_MEMBER_DANGER_THRESHOLD    (MaxMultiXactOffset - MaxMultiXactOffset / 4)

Definition at line 213 of file multixact.c.

◆ MULTIXACT_MEMBER_SAFE_THRESHOLD

#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)

Definition at line 212 of file multixact.c.

◆ MULTIXACT_MEMBERGROUP_SIZE

#define MULTIXACT_MEMBERGROUP_SIZE    (sizeof(TransactionId) * MULTIXACT_MEMBERS_PER_MEMBERGROUP + MULTIXACT_FLAGBYTES_PER_GROUP)

Definition at line 148 of file multixact.c.

◆ MULTIXACT_MEMBERGROUPS_PER_PAGE

#define MULTIXACT_MEMBERGROUPS_PER_PAGE   (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)

Definition at line 150 of file multixact.c.

◆ MULTIXACT_MEMBERS_PER_MEMBERGROUP

#define MULTIXACT_MEMBERS_PER_MEMBERGROUP    (MULTIXACT_FLAGBYTES_PER_GROUP * MXACT_MEMBER_FLAGS_PER_BYTE)

Definition at line 145 of file multixact.c.

◆ MULTIXACT_MEMBERS_PER_PAGE

#define MULTIXACT_MEMBERS_PER_PAGE    (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)

Definition at line 151 of file multixact.c.

◆ MULTIXACT_OFFSETS_PER_PAGE

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))

Definition at line 106 of file multixact.c.

◆ MultiXactMemberCtl

#define MultiXactMemberCtl   (&MultiXactMemberCtlData)

Definition at line 229 of file multixact.c.

◆ MultiXactOffsetCtl

#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)

Definition at line 228 of file multixact.c.

◆ MXACT_MEMBER_BITS_PER_XACT

#define MXACT_MEMBER_BITS_PER_XACT   8

Definition at line 139 of file multixact.c.

◆ MXACT_MEMBER_FLAGS_PER_BYTE

#define MXACT_MEMBER_FLAGS_PER_BYTE   1

Definition at line 140 of file multixact.c.

◆ MXACT_MEMBER_XACT_BITMASK

#define MXACT_MEMBER_XACT_BITMASK   ((1 << MXACT_MEMBER_BITS_PER_XACT) - 1)

Definition at line 141 of file multixact.c.

◆ OFFSET_WARN_SEGMENTS

#define OFFSET_WARN_SEGMENTS   20

◆ SHARED_MULTIXACT_STATE_SIZE

#define SHARED_MULTIXACT_STATE_SIZE
Value:
add_size(offsetof(MultiXactStateData, perBackendXactIds), \
TransactionId MultiXactId
Definition: c.h:667
#define MaxOldestSlot
Definition: multixact.c:333
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510

Typedef Documentation

◆ MultiXactStateData

◆ mXactCacheEnt

typedef struct mXactCacheEnt mXactCacheEnt

◆ mxtruncinfo

typedef struct mxtruncinfo mxtruncinfo

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1799 of file multixact.c.

1800{
1801 /*
1802 * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1803 * which should only be valid while within a transaction.
1804 *
1805 * We assume that storing a MultiXactId is atomic and so we need not take
1806 * MultiXactGenLock to do this.
1807 */
1810
1811 /*
1812 * Discard the local MultiXactId cache. Since MXactContext was created as
1813 * a child of TopTransactionContext, we needn't delete it explicitly.
1814 */
1815 MXactContext = NULL;
1817}
ProcNumber MyProcNumber
Definition: globals.c:90
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:368
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:338
static dclist_head MXactCache
Definition: multixact.c:367
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:337
#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 1827 of file multixact.c.

1828{
1830
1831 if (MultiXactIdIsValid(myOldestMember))
1833 &myOldestMember, sizeof(MultiXactId));
1834}
#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 2025 of file multixact.c.

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

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruZeroAndWritePage().

Referenced by BootStrapXLOG().

◆ check_multixact_member_buffers()

bool check_multixact_member_buffers ( int *  newval,
void **  extra,
GucSource  source 
)

Definition at line 2014 of file multixact.c.

2015{
2016 return check_slru_buffers("multixact_member_buffers", newval);
2017}
#define newval
bool check_slru_buffers(const char *name, int *newval)
Definition: slru.c:355

References check_slru_buffers(), and newval.

◆ check_multixact_offset_buffers()

bool check_multixact_offset_buffers ( int *  newval,
void **  extra,
GucSource  source 
)

Definition at line 2005 of file multixact.c.

2006{
2007 return check_slru_buffers("multixact_offset_buffers", newval);
2008}

References check_slru_buffers(), and newval.

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2234 of file multixact.c.

2235{
2236 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2237
2238 /*
2239 * Write dirty MultiXact pages to disk. This may result in sync requests
2240 * queued for later handling by ProcessSyncRequests(), as part of the
2241 * checkpoint.
2242 */
2245
2246 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2247}
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1347

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ ExtendMultiXactMember()

static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2517 of file multixact.c.

2518{
2519 /*
2520 * It's possible that the members span more than one page of the members
2521 * file, so we loop to ensure we consider each page. The coding is not
2522 * optimal if the members span several pages, but that seems unusual
2523 * enough to not worry much about.
2524 */
2525 while (nmembers > 0)
2526 {
2527 int flagsoff;
2528 int flagsbit;
2530
2531 /*
2532 * Only zero when at first entry of a page.
2533 */
2534 flagsoff = MXOffsetToFlagsOffset(offset);
2535 flagsbit = MXOffsetToFlagsBitShift(offset);
2536 if (flagsoff == 0 && flagsbit == 0)
2537 {
2538 int64 pageno;
2539 LWLock *lock;
2540
2541 pageno = MXOffsetToMemberPage(offset);
2543
2545
2546 /* Zero the page and make a WAL entry about it */
2548 XLogSimpleInsertInt64(RM_MULTIXACT_ID,
2550
2551 LWLockRelease(lock);
2552 }
2553
2554 /*
2555 * Compute the number of items till end of current page. Careful: if
2556 * addition of unsigned ints wraps around, we're at the last page of
2557 * the last segment; since that page holds a different number of items
2558 * than other pages, we need to do it differently.
2559 */
2560 if (offset + MAX_MEMBERS_IN_LAST_MEMBERS_PAGE < offset)
2561 {
2562 /*
2563 * This is the last page of the last segment; we can compute the
2564 * number of items left to allocate in it without modulo
2565 * arithmetic.
2566 */
2567 difference = MaxMultiXactOffset - offset + 1;
2568 }
2569 else
2571
2572 /*
2573 * Advance to next page, taking care to properly handle the wraparound
2574 * case. OK if nmembers goes negative.
2575 */
2576 nmembers -= difference;
2577 offset += difference;
2578 }
2579}
int64_t int64
Definition: c.h:535
uint32_t uint32
Definition: c.h:538
Datum difference(PG_FUNCTION_ARGS)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_EXCLUSIVE
Definition: lwlock.h:112
static int64 MXOffsetToMemberPage(MultiXactOffset offset)
Definition: multixact.c:169
static int MXOffsetToFlagsOffset(MultiXactOffset offset)
Definition: multixact.c:182
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE
Definition: multixact.c:164
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:151
static int MXOffsetToFlagsBitShift(MultiXactOffset offset)
Definition: multixact.c:192
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:70
#define MaxMultiXactOffset
Definition: multixact.h:31
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:375
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:175
Definition: lwlock.h:42
XLogRecPtr XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value)
Definition: xloginsert.c:537

References difference(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAX_MEMBERS_IN_LAST_MEMBERS_PAGE, MaxMultiXactOffset, MULTIXACT_MEMBERS_PER_PAGE, MultiXactMemberCtl, MXOffsetToFlagsBitShift(), MXOffsetToFlagsOffset(), MXOffsetToMemberPage(), SimpleLruGetBankLock(), SimpleLruZeroPage(), XLOG_MULTIXACT_ZERO_MEM_PAGE, and XLogSimpleInsertInt64().

Referenced by GetNewMultiXactId().

◆ ExtendMultiXactOffset()

static void ExtendMultiXactOffset ( MultiXactId  multi)
static

Definition at line 2483 of file multixact.c.

2484{
2485 int64 pageno;
2486 LWLock *lock;
2487
2488 /*
2489 * No work except at first MultiXactId of a page. But beware: just after
2490 * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2491 */
2492 if (MultiXactIdToOffsetEntry(multi) != 0 &&
2493 multi != FirstMultiXactId)
2494 return;
2495
2496 pageno = MultiXactIdToOffsetPage(multi);
2498
2500
2501 /* Zero the page and make a WAL entry about it */
2504 pageno);
2505
2506 LWLockRelease(lock);
2507}
static int MultiXactIdToOffsetEntry(MultiXactId multi)
Definition: multixact.c:115
static int64 MultiXactIdToOffsetPage(MultiXactId multi)
Definition: multixact.c:109
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:69
#define FirstMultiXactId
Definition: multixact.h:26

References FirstMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdToOffsetEntry(), MultiXactIdToOffsetPage(), MultiXactOffsetCtl, SimpleLruGetBankLock(), SimpleLruZeroPage(), XLOG_MULTIXACT_ZERO_OFF_PAGE, and XLogSimpleInsertInt64().

Referenced by GetNewMultiXactId().

◆ find_multixact_start()

static bool find_multixact_start ( MultiXactId  multi,
MultiXactOffset result 
)
static

Definition at line 2822 of file multixact.c.

2823{
2824 MultiXactOffset offset;
2825 int64 pageno;
2826 int entryno;
2827 int slotno;
2828 MultiXactOffset *offptr;
2829
2831
2832 pageno = MultiXactIdToOffsetPage(multi);
2833 entryno = MultiXactIdToOffsetEntry(multi);
2834
2835 /*
2836 * Write out dirty data, so PhysicalPageExists can work correctly.
2837 */
2840
2842 return false;
2843
2844 /* lock is acquired by SimpleLruReadPage_ReadOnly */
2845 slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2846 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2847 offptr += entryno;
2848 offset = *offptr;
2850
2851 *result = offset;
2852 return true;
2853}
uint32 MultiXactOffset
Definition: c.h:669
Assert(PointerIsAligned(start, uint64))
static MultiXactStateData * MultiXactState
Definition: multixact.c:336
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:630
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int64 pageno)
Definition: slru.c:771

References Assert(), MultiXactStateData::finishedStartup, LWLockRelease(), MultiXactIdToOffsetEntry(), MultiXactIdToOffsetPage(), MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, SimpleLruDoesPhysicalPageExist(), SimpleLruGetBankLock(), SimpleLruReadPage_ReadOnly(), and SimpleLruWriteAll().

Referenced by SetOffsetVacuumLimit(), and TruncateMultiXact().

◆ GetMultiXactIdMembers()

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

Definition at line 1290 of file multixact.c.

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

◆ GetMultiXactInfo()

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

Definition at line 2867 of file multixact.c.

2869{
2870 MultiXactOffset nextOffset;
2871 MultiXactId nextMultiXactId;
2872 bool oldestOffsetKnown;
2873
2874 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2875 nextOffset = MultiXactState->nextOffset;
2876 *oldestMultiXactId = MultiXactState->oldestMultiXactId;
2877 nextMultiXactId = MultiXactState->nextMXact;
2878 *oldestOffset = MultiXactState->oldestOffset;
2879 oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2880 LWLockRelease(MultiXactGenLock);
2881
2882 if (!oldestOffsetKnown)
2883 {
2884 *members = 0;
2885 *multixacts = 0;
2886 *oldestMultiXactId = InvalidMultiXactId;
2887 *oldestOffset = 0;
2888 return false;
2889 }
2890
2891 *members = nextOffset - *oldestOffset;
2892 *multixacts = nextMultiXactId - *oldestMultiXactId;
2893 return true;
2894}
MultiXactOffset oldestOffset
Definition: multixact.c:262

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

Referenced by MultiXactMemberFreezeThreshold().

◆ GetNewMultiXactId()

static MultiXactId GetNewMultiXactId ( int  nmembers,
MultiXactOffset offset 
)
static

Definition at line 1023 of file multixact.c.

1024{
1025 MultiXactId result;
1026 MultiXactOffset nextOffset;
1027
1028 debug_elog3(DEBUG2, "GetNew: for %d xids", nmembers);
1029
1030 /* safety check, we should never get this far in a HS standby */
1031 if (RecoveryInProgress())
1032 elog(ERROR, "cannot assign MultiXactIds during recovery");
1033
1034 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1035
1036 /* Handle wraparound of the nextMXact counter */
1039
1040 /* Assign the MXID */
1041 result = MultiXactState->nextMXact;
1042
1043 /*----------
1044 * Check to see if it's safe to assign another MultiXactId. This protects
1045 * against catastrophic data loss due to multixact wraparound. The basic
1046 * rules are:
1047 *
1048 * If we're past multiVacLimit or the safe threshold for member storage
1049 * space, or we don't know what the safe threshold for member storage is,
1050 * start trying to force autovacuum cycles.
1051 * If we're past multiWarnLimit, start issuing warnings.
1052 * If we're past multiStopLimit, refuse to create new MultiXactIds.
1053 *
1054 * Note these are pretty much the same protections in GetNewTransactionId.
1055 *----------
1056 */
1058 {
1059 /*
1060 * For safety's sake, we release MultiXactGenLock while sending
1061 * signals, warnings, etc. This is not so much because we care about
1062 * preserving concurrency in this situation, as to avoid any
1063 * possibility of deadlock while doing get_database_name(). First,
1064 * copy all the shared values we'll need in this path.
1065 */
1066 MultiXactId multiWarnLimit = MultiXactState->multiWarnLimit;
1067 MultiXactId multiStopLimit = MultiXactState->multiStopLimit;
1068 MultiXactId multiWrapLimit = MultiXactState->multiWrapLimit;
1069 Oid oldest_datoid = MultiXactState->oldestMultiXactDB;
1070
1071 LWLockRelease(MultiXactGenLock);
1072
1073 if (IsUnderPostmaster &&
1074 !MultiXactIdPrecedes(result, multiStopLimit))
1075 {
1076 char *oldest_datname = get_database_name(oldest_datoid);
1077
1078 /*
1079 * Immediately kick autovacuum into action as we're already in
1080 * ERROR territory.
1081 */
1083
1084 /* complain even if that DB has disappeared */
1085 if (oldest_datname)
1086 ereport(ERROR,
1087 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1088 errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database \"%s\"",
1089 oldest_datname),
1090 errhint("Execute a database-wide VACUUM in that database.\n"
1091 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1092 else
1093 ereport(ERROR,
1094 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1095 errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database with OID %u",
1096 oldest_datoid),
1097 errhint("Execute a database-wide VACUUM in that database.\n"
1098 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1099 }
1100
1101 /*
1102 * To avoid swamping the postmaster with signals, we issue the autovac
1103 * request only once per 64K multis generated. This still gives
1104 * plenty of chances before we get into real trouble.
1105 */
1106 if (IsUnderPostmaster && (result % 65536) == 0)
1108
1109 if (!MultiXactIdPrecedes(result, multiWarnLimit))
1110 {
1111 char *oldest_datname = get_database_name(oldest_datoid);
1112
1113 /* complain even if that DB has disappeared */
1114 if (oldest_datname)
1116 (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
1117 "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
1118 multiWrapLimit - result,
1119 oldest_datname,
1120 multiWrapLimit - result),
1121 errhint("Execute a database-wide VACUUM in that database.\n"
1122 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1123 else
1125 (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
1126 "database with OID %u must be vacuumed before %u more MultiXactIds are used",
1127 multiWrapLimit - result,
1128 oldest_datoid,
1129 multiWrapLimit - result),
1130 errhint("Execute a database-wide VACUUM in that database.\n"
1131 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1132 }
1133
1134 /* Re-acquire lock and start over */
1135 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1136 result = MultiXactState->nextMXact;
1137 if (result < FirstMultiXactId)
1138 result = FirstMultiXactId;
1139 }
1140
1141 /* Make sure there is room for the MXID in the file. */
1142 ExtendMultiXactOffset(result);
1143
1144 /*
1145 * Reserve the members space, similarly to above. Also, be careful not to
1146 * return zero as the starting offset for any multixact. See
1147 * GetMultiXactIdMembers() for motivation.
1148 */
1149 nextOffset = MultiXactState->nextOffset;
1150 if (nextOffset == 0)
1151 {
1152 *offset = 1;
1153 nmembers++; /* allocate member slot 0 too */
1154 }
1155 else
1156 *offset = nextOffset;
1157
1158 /*----------
1159 * Protect against overrun of the members space as well, with the
1160 * following rules:
1161 *
1162 * If we're past offsetStopLimit, refuse to generate more multis.
1163 * If we're close to offsetStopLimit, emit a warning.
1164 *
1165 * Arbitrarily, we start emitting warnings when we're 20 segments or less
1166 * from offsetStopLimit.
1167 *
1168 * Note we haven't updated the shared state yet, so if we fail at this
1169 * point, the multixact ID we grabbed can still be used by the next guy.
1170 *
1171 * Note that there is no point in forcing autovacuum runs here: the
1172 * multixact freeze settings would have to be reduced for that to have any
1173 * effect.
1174 *----------
1175 */
1176#define OFFSET_WARN_SEGMENTS 20
1179 nmembers))
1180 {
1181 /* see comment in the corresponding offsets wraparound case */
1183
1184 ereport(ERROR,
1185 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1186 errmsg("multixact \"members\" limit exceeded"),
1187 errdetail_plural("This command would create a multixact with %u members, but the remaining space is only enough for %u member.",
1188 "This command would create a multixact with %u members, but the remaining space is only enough for %u members.",
1189 MultiXactState->offsetStopLimit - nextOffset - 1,
1190 nmembers,
1191 MultiXactState->offsetStopLimit - nextOffset - 1),
1192 errhint("Execute a database-wide VACUUM in database with OID %u with reduced \"vacuum_multixact_freeze_min_age\" and \"vacuum_multixact_freeze_table_age\" settings.",
1194 }
1195
1196 /*
1197 * Check whether we should kick autovacuum into action, to prevent members
1198 * wraparound. NB we use a much larger window to trigger autovacuum than
1199 * just the warning limit. The warning is just a measure of last resort -
1200 * this is in line with GetNewTransactionId's behaviour.
1201 */
1205 {
1206 /*
1207 * To avoid swamping the postmaster with signals, we issue the autovac
1208 * request only when crossing a segment boundary. With default
1209 * compilation settings that's roughly after 50k members. This still
1210 * gives plenty of chances before we get into real trouble.
1211 */
1212 if ((MXOffsetToMemberPage(nextOffset) / SLRU_PAGES_PER_SEGMENT) !=
1213 (MXOffsetToMemberPage(nextOffset + nmembers) / SLRU_PAGES_PER_SEGMENT))
1215 }
1216
1219 nextOffset,
1222 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1223 errmsg_plural("database with OID %u must be vacuumed before %d more multixact member is used",
1224 "database with OID %u must be vacuumed before %d more multixact members are used",
1225 MultiXactState->offsetStopLimit - nextOffset + nmembers,
1227 MultiXactState->offsetStopLimit - nextOffset + nmembers),
1228 errhint("Execute a database-wide VACUUM in that database with reduced \"vacuum_multixact_freeze_min_age\" and \"vacuum_multixact_freeze_table_age\" settings.")));
1229
1230 ExtendMultiXactMember(nextOffset, nmembers);
1231
1232 /*
1233 * Critical section from here until caller has written the data into the
1234 * just-reserved SLRU space; we don't want to error out with a partly
1235 * written MultiXact structure. (In particular, failing to write our
1236 * start offset after advancing nextMXact would effectively corrupt the
1237 * previous MultiXact.)
1238 */
1240
1241 /*
1242 * Advance counters. As in GetNewTransactionId(), this must not happen
1243 * until after file extension has succeeded!
1244 *
1245 * We don't care about MultiXactId wraparound here; it will be handled by
1246 * the next iteration. But note that nextMXact may be InvalidMultiXactId
1247 * or the first value on a segment-beginning page after this routine
1248 * exits, so anyone else looking at the variable must be prepared to deal
1249 * with either case. Similarly, nextOffset may be zero, but we won't use
1250 * that as the actual start offset of the next multixact.
1251 */
1253
1254 MultiXactState->nextOffset += nmembers;
1255
1256 LWLockRelease(MultiXactGenLock);
1257
1258 debug_elog4(DEBUG2, "GetNew: returning %u offset %u", result, *offset);
1259 return result;
1260}
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1184
int errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1299
int errhint(const char *fmt,...)
Definition: elog.c:1321
#define WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:226
bool IsUnderPostmaster
Definition: globals.c:120
char * get_database_name(Oid dbid)
Definition: lsyscache.c:1259
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:212
static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
Definition: multixact.c:2517
static bool MultiXactOffsetWouldWrap(MultiXactOffset boundary, MultiXactOffset start, uint32 distance)
Definition: multixact.c:2774
static void ExtendMultiXactOffset(MultiXactId multi)
Definition: multixact.c:2483
#define debug_elog4(a, b, c, d)
Definition: multixact.c:379
#define OFFSET_WARN_SEGMENTS
void SendPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:165
@ PMSIGNAL_START_AUTOVAC_LAUNCHER
Definition: pmsignal.h:39
unsigned int Oid
Definition: postgres_ext.h:32
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:39
MultiXactId multiWrapLimit
Definition: multixact.c:269
MultiXactId multiStopLimit
Definition: multixact.c:268
MultiXactId multiWarnLimit
Definition: multixact.c:267
MultiXactId multiVacLimit
Definition: multixact.c:266
MultiXactOffset offsetStopLimit
Definition: multixact.c:272
bool RecoveryInProgress(void)
Definition: xlog.c:6386

References DEBUG2, debug_elog3, debug_elog4, elog, ereport, errcode(), errdetail_plural(), errhint(), errmsg(), errmsg_plural(), ERROR, ExtendMultiXactMember(), ExtendMultiXactOffset(), FirstMultiXactId, get_database_name(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactStateData::multiStopLimit, MultiXactStateData::multiVacLimit, MultiXactStateData::multiWarnLimit, MultiXactStateData::multiWrapLimit, MULTIXACT_MEMBER_SAFE_THRESHOLD, MULTIXACT_MEMBERS_PER_PAGE, MultiXactIdPrecedes(), MultiXactOffsetWouldWrap(), MultiXactState, MXOffsetToMemberPage(), MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, OFFSET_WARN_SEGMENTS, MultiXactStateData::offsetStopLimit, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestOffset, MultiXactStateData::oldestOffsetKnown, PMSIGNAL_START_AUTOVAC_LAUNCHER, RecoveryInProgress(), SendPostmasterSignal(), SLRU_PAGES_PER_SEGMENT, START_CRIT_SECTION, and WARNING.

Referenced by MultiXactIdCreateFromMembers().

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2594 of file multixact.c.

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

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

◆ MaybeExtendOffsetSlru()

static void MaybeExtendOffsetSlru ( void  )
static

Definition at line 2048 of file multixact.c.

2049{
2050 int64 pageno;
2051 LWLock *lock;
2052
2055
2057
2059 {
2060 int slotno;
2061
2062 /*
2063 * Fortunately for us, SimpleLruWritePage is already prepared to deal
2064 * with creating a new segment file even if the page we're writing is
2065 * not the first in it, so this is enough.
2066 */
2067 slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
2069 }
2070
2071 LWLockRelease(lock);
2072}
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:757

References LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdToOffsetPage(), MultiXactOffsetCtl, MultiXactState, MultiXactStateData::nextMXact, SimpleLruDoesPhysicalPageExist(), SimpleLruGetBankLock(), SimpleLruWritePage(), and SimpleLruZeroPage().

Referenced by MultiXactSetNextMXact().

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 3330 of file multixact.c.

3331{
3332 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3333
3334 /* Backup blocks are not used in multixact records */
3336
3337 if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3338 {
3339 int64 pageno;
3340
3341 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3343 }
3344 else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3345 {
3346 int64 pageno;
3347
3348 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3350 }
3351 else if (info == XLOG_MULTIXACT_CREATE_ID)
3352 {
3353 xl_multixact_create *xlrec =
3355 TransactionId max_xid;
3356 int i;
3357
3358 /* Store the data back into the SLRU files */
3359 RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3360 xlrec->members);
3361
3362 /* Make sure nextMXact/nextOffset are beyond what this record has */
3363 MultiXactAdvanceNextMXact(xlrec->mid + 1,
3364 xlrec->moff + xlrec->nmembers);
3365
3366 /*
3367 * Make sure nextXid is beyond any XID mentioned in the record. This
3368 * should be unnecessary, since any XID found here ought to have other
3369 * evidence in the XLOG, but let's be safe.
3370 */
3371 max_xid = XLogRecGetXid(record);
3372 for (i = 0; i < xlrec->nmembers; i++)
3373 {
3374 if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3375 max_xid = xlrec->members[i].xid;
3376 }
3377
3379 }
3380 else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3381 {
3383 int64 pageno;
3384
3385 memcpy(&xlrec, XLogRecGetData(record),
3387
3388 elog(DEBUG1, "replaying multixact truncation: "
3389 "offsets [%u, %u), offsets segments [%" PRIx64 ", %" PRIx64 "), "
3390 "members [%u, %u), members segments [%" PRIx64 ", %" PRIx64 ")",
3391 xlrec.startTruncOff, xlrec.endTruncOff,
3394 xlrec.startTruncMemb, xlrec.endTruncMemb,
3397
3398 /* should not be required, but more than cheap enough */
3399 LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3400
3401 /*
3402 * Advance the horizon values, so they're current at the end of
3403 * recovery.
3404 */
3405 SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3406
3408
3409 /*
3410 * During XLOG replay, latest_page_number isn't necessarily set up
3411 * yet; insert a suitable value to bypass the sanity test in
3412 * SimpleLruTruncate.
3413 */
3414 pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3415 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3416 pageno);
3418
3419 LWLockRelease(MultiXactTruncationLock);
3420 }
3421 else
3422 elog(PANIC, "multixact_redo: unknown op code %u", info);
3423}
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:483
uint8_t uint8
Definition: c.h:536
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
static int64 MultiXactIdToOffsetSegment(MultiXactId multi)
Definition: multixact.c:121
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:3025
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2996
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2292
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:907
static int64 MXOffsetToMemberSegment(MultiXactOffset offset)
Definition: multixact.c:175
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2441
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:72
#define SizeOfMultiXactTruncate
Definition: multixact.h:97
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:71
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
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:304
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#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(), 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 1926 of file multixact.c.

1928{
1929 multixact_twophase_postcommit(fxid, info, recdata, len);
1930}
void multixact_twophase_postcommit(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1911
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 1911 of file multixact.c.

1913{
1914 ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, true);
1915
1916 Assert(len == sizeof(MultiXactId));
1917
1918 OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1919}
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 1890 of file multixact.c.

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

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2441 of file multixact.c.

2443{
2444 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2446 {
2447 debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2448 MultiXactState->nextMXact = minMulti;
2449 }
2451 {
2452 debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2453 minMultiOffset);
2454 MultiXactState->nextOffset = minMultiOffset;
2455 }
2456 LWLockRelease(MultiXactGenLock);
2457}
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3291

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

2467{
2469
2471 SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2472}
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 2212 of file multixact.c.

2217{
2218 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2219 *nextMulti = MultiXactState->nextMXact;
2220 *nextMultiOffset = MultiXactState->nextOffset;
2221 *oldestMulti = MultiXactState->oldestMultiXactId;
2222 *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2223 LWLockRelease(MultiXactGenLock);
2224
2226 "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2227 *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2228}
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:381

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

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

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

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

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

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

3280{
3281 int32 diff = (int32) (multi1 - multi2);
3282
3283 return (diff <= 0);
3284}

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

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

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

◆ MultiXactIdSetOldestVisible()

static void MultiXactIdSetOldestVisible ( void  )
static

Definition at line 721 of file multixact.c.

722{
724 {
725 MultiXactId oldestMXact;
726 int i;
727
728 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
729
730 /*
731 * We have to beware of the possibility that nextMXact is in the
732 * wrapped-around state. We don't fix the counter itself here, but we
733 * must be sure to store a valid value in our array entry.
734 */
735 oldestMXact = MultiXactState->nextMXact;
736 if (oldestMXact < FirstMultiXactId)
737 oldestMXact = FirstMultiXactId;
738
739 for (i = 0; i < MaxOldestSlot; i++)
740 {
741 MultiXactId thisoldest = OldestMemberMXactId[i];
742
743 if (MultiXactIdIsValid(thisoldest) &&
744 MultiXactIdPrecedes(thisoldest, oldestMXact))
745 oldestMXact = thisoldest;
746 }
747
748 OldestVisibleMXactId[MyProcNumber] = oldestMXact;
749
750 LWLockRelease(MultiXactGenLock);
751
752 debug_elog4(DEBUG2, "MultiXact: setting OldestVisible[%d] = %u",
753 MyProcNumber, oldestMXact);
754 }
755}

References DEBUG2, debug_elog4, FirstMultiXactId, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxOldestSlot, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactState, MyProcNumber, MultiXactStateData::nextMXact, OldestMemberMXactId, and OldestVisibleMXactId.

Referenced by GetMultiXactIdMembers().

◆ MultiXactIdToOffsetEntry()

static int MultiXactIdToOffsetEntry ( MultiXactId  multi)
inlinestatic

Definition at line 115 of file multixact.c.

116{
117 return multi % MULTIXACT_OFFSETS_PER_PAGE;
118}
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:106

References MULTIXACT_OFFSETS_PER_PAGE.

Referenced by ExtendMultiXactOffset(), find_multixact_start(), GetMultiXactIdMembers(), RecordNewMultiXact(), and TrimMultiXact().

◆ MultiXactIdToOffsetPage()

◆ MultiXactIdToOffsetSegment()

static int64 MultiXactIdToOffsetSegment ( MultiXactId  multi)
inlinestatic

Definition at line 121 of file multixact.c.

122{
124}

References MultiXactIdToOffsetPage(), and SLRU_PAGES_PER_SEGMENT.

Referenced by multixact_redo(), and TruncateMultiXact().

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2924 of file multixact.c.

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

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

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 3245 of file multixact.c.

3246{
3247 MultiXactOffset offset1;
3248 MultiXactOffset offset2;
3249
3250 offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3251 offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3252
3253 return (MultiXactOffsetPrecedes(offset1, offset2) &&
3255 offset2 + MULTIXACT_MEMBERS_PER_PAGE - 1));
3256}

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3438 of file multixact.c.

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

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 3225 of file multixact.c.

3226{
3227 MultiXactId multi1;
3228 MultiXactId multi2;
3229
3230 multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3231 multi1 += FirstMultiXactId + 1;
3232 multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3233 multi2 += FirstMultiXactId + 1;
3234
3235 return (MultiXactIdPrecedes(multi1, multi2) &&
3236 MultiXactIdPrecedes(multi1,
3237 multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
3238}

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

◆ MultiXactOffsetPrecedes()

static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3291 of file multixact.c.

3292{
3293 int32 diff = (int32) (offset1 - offset2);
3294
3295 return (diff < 0);
3296}

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3429 of file multixact.c.

3430{
3431 return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3432}

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactOffsetWouldWrap()

static bool MultiXactOffsetWouldWrap ( MultiXactOffset  boundary,
MultiXactOffset  start,
uint32  distance 
)
static

Definition at line 2774 of file multixact.c.

2776{
2777 MultiXactOffset finish;
2778
2779 /*
2780 * Note that offset number 0 is not used (see GetMultiXactIdMembers), so
2781 * if the addition wraps around the UINT_MAX boundary, skip that value.
2782 */
2783 finish = start + distance;
2784 if (finish < start)
2785 finish++;
2786
2787 /*-----------------------------------------------------------------------
2788 * When the boundary is numerically greater than the starting point, any
2789 * value numerically between the two is not wrapped:
2790 *
2791 * <----S----B---->
2792 * [---) = F wrapped past B (and UINT_MAX)
2793 * [---) = F not wrapped
2794 * [----] = F wrapped past B
2795 *
2796 * When the boundary is numerically less than the starting point (i.e. the
2797 * UINT_MAX wraparound occurs somewhere in between) then all values in
2798 * between are wrapped:
2799 *
2800 * <----B----S---->
2801 * [---) = F not wrapped past B (but wrapped past UINT_MAX)
2802 * [---) = F wrapped past B (and UINT_MAX)
2803 * [----] = F not wrapped
2804 *-----------------------------------------------------------------------
2805 */
2806 if (start < boundary)
2807 return finish >= boundary || finish < start;
2808 else
2809 return finish >= boundary && finish < start;
2810}
return str start

References start.

Referenced by GetNewMultiXactId().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2258 of file multixact.c.

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

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

1956{
1957 bool found;
1958
1959 debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1960
1963
1965 "multixact_offset", multixact_offset_buffers, 0,
1966 "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1967 LWTRANCHE_MULTIXACTOFFSET_SLRU,
1969 false);
1972 "multixact_member", multixact_member_buffers, 0,
1973 "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1974 LWTRANCHE_MULTIXACTMEMBER_SLRU,
1976 false);
1977 /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1978
1979 /* Initialize our shared state struct */
1980 MultiXactState = ShmemInitStruct("Shared MultiXact State",
1982 &found);
1983 if (!IsUnderPostmaster)
1984 {
1985 Assert(!found);
1986
1987 /* Make sure we zero out the per-backend state */
1990 }
1991 else
1992 Assert(found);
1993
1994 /*
1995 * Set up array pointers.
1996 */
1999}
#define MemSet(start, val, len)
Definition: c.h:1019
void ConditionVariableInit(ConditionVariable *cv)
int multixact_offset_buffers
Definition: globals.c:163
int multixact_member_buffers
Definition: globals.c:162
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3245
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3225
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition: slru.c:252
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:200
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:327
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40

References Assert(), ConditionVariableInit(), DEBUG2, debug_elog2, IsUnderPostmaster, 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 1938 of file multixact.c.

1939{
1940 Size size;
1941
1942 /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1943#define SHARED_MULTIXACT_STATE_SIZE \
1944 add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1945 mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1946
1950
1951 return size;
1952}
size_t Size
Definition: c.h:610
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().

◆ mXactCacheGetById()

static int mXactCacheGetById ( MultiXactId  multi,
MultiXactMember **  members 
)
static

Definition at line 1653 of file multixact.c.

1654{
1655 dlist_iter iter;
1656
1657 debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1658
1660 {
1662 iter.cur);
1663
1664 if (entry->multi == multi)
1665 {
1666 MultiXactMember *ptr;
1667 Size size;
1668
1669 size = sizeof(MultiXactMember) * entry->nmembers;
1670 ptr = (MultiXactMember *) palloc(size);
1671
1672 memcpy(ptr, entry->members, size);
1673
1674 debug_elog3(DEBUG2, "CacheGet: found %s",
1675 mxid_to_string(multi,
1676 entry->nmembers,
1677 entry->members));
1678
1679 /*
1680 * Note we modify the list while not using a modifiable iterator.
1681 * This is acceptable only because we exit the iteration
1682 * immediately afterwards.
1683 */
1685
1686 *members = ptr;
1687 return entry->nmembers;
1688 }
1689 }
1690
1691 debug_elog2(DEBUG2, "CacheGet: not found");
1692 return -1;
1693}
#define dclist_container(type, membername, ptr)
Definition: ilist.h:947
static void dclist_move_head(dclist_head *head, dlist_node *node)
Definition: ilist.h:808
#define dclist_foreach(iter, lhead)
Definition: ilist.h:970
struct MultiXactMember MultiXactMember
dlist_node * cur
Definition: ilist.h:179
MultiXactId multi
Definition: multixact.c:360
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:363

References dlist_iter::cur, dclist_container, dclist_foreach, dclist_move_head(), DEBUG2, debug_elog2, debug_elog3, mXactCacheEnt::members, mXactCacheEnt::multi, MXactCache, mxid_to_string(), mXactCacheEnt::nmembers, and palloc().

Referenced by GetMultiXactIdMembers().

◆ mXactCacheGetBySet()

static MultiXactId mXactCacheGetBySet ( int  nmembers,
MultiXactMember members 
)
static

Definition at line 1610 of file multixact.c.

1611{
1612 dlist_iter iter;
1613
1614 debug_elog3(DEBUG2, "CacheGet: looking for %s",
1615 mxid_to_string(InvalidMultiXactId, nmembers, members));
1616
1617 /* sort the array so comparison is easy */
1618 qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1619
1621 {
1623 iter.cur);
1624
1625 if (entry->nmembers != nmembers)
1626 continue;
1627
1628 /*
1629 * We assume the cache entries are sorted, and that the unused bits in
1630 * "status" are zeroed.
1631 */
1632 if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1633 {
1634 debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1636 return entry->multi;
1637 }
1638 }
1639
1640 debug_elog2(DEBUG2, "CacheGet: not found :-(");
1641 return InvalidMultiXactId;
1642}
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition: multixact.c:1580
#define qsort(a, b, c, d)
Definition: port.h:479

References dlist_iter::cur, dclist_container, dclist_foreach, dclist_move_head(), DEBUG2, debug_elog2, debug_elog3, InvalidMultiXactId, mXactCacheEnt::members, mXactCacheEnt::multi, MXactCache, mxactMemberComparator(), mxid_to_string(), mXactCacheEnt::nmembers, and qsort.

Referenced by MultiXactIdCreateFromMembers().

◆ mXactCachePut()

static void mXactCachePut ( MultiXactId  multi,
int  nmembers,
MultiXactMember members 
)
static

Definition at line 1700 of file multixact.c.

1701{
1702 mXactCacheEnt *entry;
1703
1704 debug_elog3(DEBUG2, "CachePut: storing %s",
1705 mxid_to_string(multi, nmembers, members));
1706
1707 if (MXactContext == NULL)
1708 {
1709 /* The cache only lives as long as the current transaction */
1710 debug_elog2(DEBUG2, "CachePut: initializing memory context");
1712 "MultiXact cache context",
1714 }
1715
1716 entry = (mXactCacheEnt *)
1718 offsetof(mXactCacheEnt, members) +
1719 nmembers * sizeof(MultiXactMember));
1720
1721 entry->multi = multi;
1722 entry->nmembers = nmembers;
1723 memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1724
1725 /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1726 qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1727
1728 dclist_push_head(&MXactCache, &entry->node);
1730 {
1731 dlist_node *node;
1732
1735
1736 entry = dclist_container(mXactCacheEnt, node, node);
1737 debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1738 entry->multi);
1739
1740 pfree(entry);
1741 }
1742}
static uint32 dclist_count(const dclist_head *head)
Definition: ilist.h:932
static dlist_node * dclist_tail_node(dclist_head *head)
Definition: ilist.h:920
static void dclist_delete_from(dclist_head *head, dlist_node *node)
Definition: ilist.h:763
static void dclist_push_head(dclist_head *head, dlist_node *node)
Definition: ilist.h:693
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1229
MemoryContext TopTransactionContext
Definition: mcxt.c:171
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
#define MAX_CACHE_ENTRIES
Definition: multixact.c:366
dlist_node node
Definition: multixact.c:362

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, dclist_container, dclist_count(), dclist_delete_from(), dclist_push_head(), dclist_tail_node(), DEBUG2, debug_elog2, debug_elog3, MAX_CACHE_ENTRIES, mXactCacheEnt::members, MemoryContextAlloc(), mXactCacheEnt::multi, MXactCache, MXactContext, mxactMemberComparator(), mxid_to_string(), mXactCacheEnt::nmembers, mXactCacheEnt::node, pfree(), qsort, and TopTransactionContext.

Referenced by GetMultiXactIdMembers(), and MultiXactIdCreateFromMembers().

◆ mxactMemberComparator()

static int mxactMemberComparator ( const void *  arg1,
const void *  arg2 
)
static

Definition at line 1580 of file multixact.c.

1581{
1582 MultiXactMember member1 = *(const MultiXactMember *) arg1;
1583 MultiXactMember member2 = *(const MultiXactMember *) arg2;
1584
1585 if (member1.xid > member2.xid)
1586 return 1;
1587 if (member1.xid < member2.xid)
1588 return -1;
1589 if (member1.status > member2.status)
1590 return 1;
1591 if (member1.status < member2.status)
1592 return -1;
1593 return 0;
1594}

References MultiXactMember::status, and MultiXactMember::xid.

Referenced by mXactCacheGetBySet(), and mXactCachePut().

◆ mxid_to_string()

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

Definition at line 1768 of file multixact.c.

1769{
1770 static char *str = NULL;
1772 int i;
1773
1774 if (str != NULL)
1775 pfree(str);
1776
1778
1779 appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1780 mxstatus_to_string(members[0].status));
1781
1782 for (i = 1; i < nmembers; i++)
1783 appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1784 mxstatus_to_string(members[i].status));
1785
1788 pfree(buf.data);
1789 return str;
1790}
const char * str
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1746
MemoryContext TopMemoryContext
Definition: mcxt.c:166
static char * buf
Definition: pg_test_fsync.c:72
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
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().

◆ MXOffsetToFlagsBitShift()

static int MXOffsetToFlagsBitShift ( MultiXactOffset  offset)
inlinestatic

Definition at line 192 of file multixact.c.

193{
194 int member_in_group = offset % MULTIXACT_MEMBERS_PER_MEMBERGROUP;
195 int bshift = member_in_group * MXACT_MEMBER_BITS_PER_XACT;
196
197 return bshift;
198}
#define MXACT_MEMBER_BITS_PER_XACT
Definition: multixact.c:139
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP
Definition: multixact.c:145

References MULTIXACT_MEMBERS_PER_MEMBERGROUP, and MXACT_MEMBER_BITS_PER_XACT.

Referenced by ExtendMultiXactMember(), GetMultiXactIdMembers(), and RecordNewMultiXact().

◆ MXOffsetToFlagsOffset()

static int MXOffsetToFlagsOffset ( MultiXactOffset  offset)
inlinestatic

Definition at line 182 of file multixact.c.

183{
185 int grouponpg = group % MULTIXACT_MEMBERGROUPS_PER_PAGE;
186 int byteoff = grouponpg * MULTIXACT_MEMBERGROUP_SIZE;
187
188 return byteoff;
189}
#define MULTIXACT_MEMBERGROUPS_PER_PAGE
Definition: multixact.c:150
#define MULTIXACT_MEMBERGROUP_SIZE
Definition: multixact.c:148

References MULTIXACT_MEMBERGROUP_SIZE, MULTIXACT_MEMBERGROUPS_PER_PAGE, and MULTIXACT_MEMBERS_PER_MEMBERGROUP.

Referenced by ExtendMultiXactMember(), GetMultiXactIdMembers(), MXOffsetToMemberOffset(), RecordNewMultiXact(), and TrimMultiXact().

◆ MXOffsetToMemberOffset()

static int MXOffsetToMemberOffset ( MultiXactOffset  offset)
inlinestatic

Definition at line 202 of file multixact.c.

203{
204 int member_in_group = offset % MULTIXACT_MEMBERS_PER_MEMBERGROUP;
205
206 return MXOffsetToFlagsOffset(offset) +
208 member_in_group * sizeof(TransactionId);
209}
#define MULTIXACT_FLAGBYTES_PER_GROUP
Definition: multixact.c:144

References MULTIXACT_FLAGBYTES_PER_GROUP, MULTIXACT_MEMBERS_PER_MEMBERGROUP, and MXOffsetToFlagsOffset().

Referenced by GetMultiXactIdMembers(), RecordNewMultiXact(), and TrimMultiXact().

◆ MXOffsetToMemberPage()

static int64 MXOffsetToMemberPage ( MultiXactOffset  offset)
inlinestatic

◆ MXOffsetToMemberSegment()

static int64 MXOffsetToMemberSegment ( MultiXactOffset  offset)
inlinestatic

Definition at line 175 of file multixact.c.

176{
178}

References MXOffsetToMemberPage(), and SLRU_PAGES_PER_SEGMENT.

Referenced by multixact_redo(), PerformMembersTruncation(), and TruncateMultiXact().

◆ mxstatus_to_string()

char * mxstatus_to_string ( MultiXactStatus  status)

Definition at line 1745 of file multixact.c.

1746{
1747 switch (status)
1748 {
1750 return "keysh";
1752 return "sh";
1754 return "fornokeyupd";
1756 return "forupd";
1758 return "nokeyupd";
1760 return "upd";
1761 default:
1762 elog(ERROR, "unrecognized multixact status %d", status);
1763 return "";
1764 }
1765}
@ 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

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

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

◆ PerformMembersTruncation()

static void PerformMembersTruncation ( MultiXactOffset  oldestOffset,
MultiXactOffset  newOldestOffset 
)
static

Definition at line 2996 of file multixact.c.

2997{
2999 int64 startsegment = MXOffsetToMemberSegment(oldestOffset);
3000 int64 endsegment = MXOffsetToMemberSegment(newOldestOffset);
3001 int64 segment = startsegment;
3002
3003 /*
3004 * Delete all the segments but the last one. The last segment can still
3005 * contain, possibly partially, valid data.
3006 */
3007 while (segment != endsegment)
3008 {
3009 elog(DEBUG2, "truncating multixact members segment %" PRIx64,
3010 segment);
3012
3013 /* move to next segment, handling wraparound correctly */
3014 if (segment == maxsegment)
3015 segment = 0;
3016 else
3017 segment += 1;
3018 }
3019}
void SlruDeleteSegment(SlruCtl ctl, int64 segno)
Definition: slru.c:1551

References DEBUG2, elog, MaxMultiXactOffset, MultiXactMemberCtl, MXOffsetToMemberSegment(), and SlruDeleteSegment().

Referenced by multixact_redo(), and TruncateMultiXact().

◆ PerformOffsetsTruncation()

static void PerformOffsetsTruncation ( MultiXactId  oldestMulti,
MultiXactId  newOldestMulti 
)
static

Definition at line 3025 of file multixact.c.

3026{
3027 /*
3028 * We step back one multixact to avoid passing a cutoff page that hasn't
3029 * been created yet in the rare case that oldestMulti would be the first
3030 * item on a page and oldestMulti == nextMulti. In that case, if we
3031 * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
3032 * detection.
3033 */
3036}
static MultiXactId PreviousMultiXactId(MultiXactId multi)
Definition: multixact.c:217
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition: slru.c:1433

References MultiXactIdToOffsetPage(), MultiXactOffsetCtl, PreviousMultiXactId(), and SimpleLruTruncate().

Referenced by multixact_redo(), and TruncateMultiXact().

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( FullTransactionId  fxid)

Definition at line 1841 of file multixact.c.

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

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

Referenced by PrepareTransaction().

◆ PreviousMultiXactId()

static MultiXactId PreviousMultiXactId ( MultiXactId  multi)
inlinestatic

Definition at line 217 of file multixact.c.

218{
219 return multi == FirstMultiXactId ? MaxMultiXactId : multi - 1;
220}
#define MaxMultiXactId
Definition: multixact.h:27

References FirstMultiXactId, and MaxMultiXactId.

Referenced by PerformOffsetsTruncation().

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 782 of file multixact.c.

783{
784 LWLockAcquire(MultiXactGenLock, LW_SHARED);
787 LWLockRelease(MultiXactGenLock);
788
789 if (*oldest < FirstMultiXactId)
790 *oldest = FirstMultiXactId;
791 if (*next < FirstMultiXactId)
793}
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 762 of file multixact.c.

763{
764 MultiXactId mxid;
765
766 /* XXX we could presumably do this without a lock. */
767 LWLockAcquire(MultiXactGenLock, LW_SHARED);
769 LWLockRelease(MultiXactGenLock);
770
771 if (mxid < FirstMultiXactId)
772 mxid = FirstMultiXactId;
773
774 return mxid;
775}

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

◆ RecordNewMultiXact()

static void RecordNewMultiXact ( MultiXactId  multi,
MultiXactOffset  offset,
int  nmembers,
MultiXactMember members 
)
static

Definition at line 907 of file multixact.c.

909{
910 int64 pageno;
911 int64 prev_pageno;
912 int entryno;
913 int slotno;
914 MultiXactOffset *offptr;
915 int i;
916 LWLock *lock;
917 LWLock *prevlock = NULL;
918
919 pageno = MultiXactIdToOffsetPage(multi);
920 entryno = MultiXactIdToOffsetEntry(multi);
921
924
925 /*
926 * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
927 * to complain about if there's any I/O error. This is kinda bogus, but
928 * since the errors will always give the full pathname, it should be clear
929 * enough that a MultiXactId is really involved. Perhaps someday we'll
930 * take the trouble to generalize the slru.c error reporting code.
931 */
932 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
933 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
934 offptr += entryno;
935
936 *offptr = offset;
937
938 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
939
940 /* Release MultiXactOffset SLRU lock. */
941 LWLockRelease(lock);
942
943 /*
944 * If anybody was waiting to know the offset of this multixact ID we just
945 * wrote, they can read it now, so wake them up.
946 */
948
949 prev_pageno = -1;
950
951 for (i = 0; i < nmembers; i++, offset++)
952 {
953 TransactionId *memberptr;
954 uint32 *flagsptr;
955 uint32 flagsval;
956 int bshift;
957 int flagsoff;
958 int memberoff;
959
960 Assert(members[i].status <= MultiXactStatusUpdate);
961
962 pageno = MXOffsetToMemberPage(offset);
963 memberoff = MXOffsetToMemberOffset(offset);
964 flagsoff = MXOffsetToFlagsOffset(offset);
965 bshift = MXOffsetToFlagsBitShift(offset);
966
967 if (pageno != prev_pageno)
968 {
969 /*
970 * MultiXactMember SLRU page is changed so check if this new page
971 * fall into the different SLRU bank then release the old bank's
972 * lock and acquire lock on the new bank.
973 */
975 if (lock != prevlock)
976 {
977 if (prevlock != NULL)
978 LWLockRelease(prevlock);
979
981 prevlock = lock;
982 }
983 slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
984 prev_pageno = pageno;
985 }
986
987 memberptr = (TransactionId *)
988 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
989
990 *memberptr = members[i].xid;
991
992 flagsptr = (uint32 *)
993 (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
994
995 flagsval = *flagsptr;
996 flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
997 flagsval |= (members[i].status << bshift);
998 *flagsptr = flagsval;
999
1000 MultiXactMemberCtl->shared->page_dirty[slotno] = true;
1001 }
1002
1003 if (prevlock != NULL)
1004 LWLockRelease(prevlock);
1005}
void ConditionVariableBroadcast(ConditionVariable *cv)

References Assert(), ConditionVariableBroadcast(), i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdToOffsetEntry(), MultiXactIdToOffsetPage(), MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, MultiXactStatusUpdate, MXACT_MEMBER_BITS_PER_XACT, MXOffsetToFlagsBitShift(), MXOffsetToFlagsOffset(), MXOffsetToMemberOffset(), MXOffsetToMemberPage(), MultiXactStateData::nextoff_cv, SimpleLruGetBankLock(), SimpleLruReadPage(), MultiXactMember::status, and MultiXactMember::xid.

Referenced by multixact_redo(), and MultiXactIdCreateFromMembers().

◆ SetMultiXactIdLimit()

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

Definition at line 2292 of file multixact.c.

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

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

◆ SetOffsetVacuumLimit()

static bool SetOffsetVacuumLimit ( bool  is_startup)
static

Definition at line 2647 of file multixact.c.

2648{
2649 MultiXactId oldestMultiXactId;
2650 MultiXactId nextMXact;
2651 MultiXactOffset oldestOffset = 0; /* placate compiler */
2652 MultiXactOffset prevOldestOffset;
2653 MultiXactOffset nextOffset;
2654 bool oldestOffsetKnown = false;
2655 bool prevOldestOffsetKnown;
2656 MultiXactOffset offsetStopLimit = 0;
2657 MultiXactOffset prevOffsetStopLimit;
2658
2659 /*
2660 * NB: Have to prevent concurrent truncation, we might otherwise try to
2661 * lookup an oldestMulti that's concurrently getting truncated away.
2662 */
2663 LWLockAcquire(MultiXactTruncationLock, LW_SHARED);
2664
2665 /* Read relevant fields from shared memory. */
2666 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2667 oldestMultiXactId = MultiXactState->oldestMultiXactId;
2668 nextMXact = MultiXactState->nextMXact;
2669 nextOffset = MultiXactState->nextOffset;
2670 prevOldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2671 prevOldestOffset = MultiXactState->oldestOffset;
2672 prevOffsetStopLimit = MultiXactState->offsetStopLimit;
2674 LWLockRelease(MultiXactGenLock);
2675
2676 /*
2677 * Determine the offset of the oldest multixact. Normally, we can read
2678 * the offset from the multixact itself, but there's an important special
2679 * case: if there are no multixacts in existence at all, oldestMXact
2680 * obviously can't point to one. It will instead point to the multixact
2681 * ID that will be assigned the next time one is needed.
2682 */
2683 if (oldestMultiXactId == nextMXact)
2684 {
2685 /*
2686 * When the next multixact gets created, it will be stored at the next
2687 * offset.
2688 */
2689 oldestOffset = nextOffset;
2690 oldestOffsetKnown = true;
2691 }
2692 else
2693 {
2694 /*
2695 * Figure out where the oldest existing multixact's offsets are
2696 * stored. Due to bugs in early release of PostgreSQL 9.3.X and 9.4.X,
2697 * the supposedly-earliest multixact might not really exist. We are
2698 * careful not to fail in that case.
2699 */
2700 oldestOffsetKnown =
2701 find_multixact_start(oldestMultiXactId, &oldestOffset);
2702
2703 if (oldestOffsetKnown)
2705 (errmsg_internal("oldest MultiXactId member is at offset %u",
2706 oldestOffset)));
2707 else
2708 ereport(LOG,
2709 (errmsg("MultiXact member wraparound protections are disabled because oldest checkpointed MultiXact %u does not exist on disk",
2710 oldestMultiXactId)));
2711 }
2712
2713 LWLockRelease(MultiXactTruncationLock);
2714
2715 /*
2716 * If we can, compute limits (and install them MultiXactState) to prevent
2717 * overrun of old data in the members SLRU area. We can only do so if the
2718 * oldest offset is known though.
2719 */
2720 if (oldestOffsetKnown)
2721 {
2722 /* move back to start of the corresponding segment */
2723 offsetStopLimit = oldestOffset - (oldestOffset %
2725
2726 /* always leave one segment before the wraparound point */
2728
2729 if (!prevOldestOffsetKnown && !is_startup)
2730 ereport(LOG,
2731 (errmsg("MultiXact member wraparound protections are now enabled")));
2732
2734 (errmsg_internal("MultiXact member stop limit is now %u based on MultiXact %u",
2735 offsetStopLimit, oldestMultiXactId)));
2736 }
2737 else if (prevOldestOffsetKnown)
2738 {
2739 /*
2740 * If we failed to get the oldest offset this time, but we have a
2741 * value from a previous pass through this function, use the old
2742 * values rather than automatically forcing an emergency autovacuum
2743 * cycle again.
2744 */
2745 oldestOffset = prevOldestOffset;
2746 oldestOffsetKnown = true;
2747 offsetStopLimit = prevOffsetStopLimit;
2748 }
2749
2750 /* Install the computed values */
2751 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2752 MultiXactState->oldestOffset = oldestOffset;
2753 MultiXactState->oldestOffsetKnown = oldestOffsetKnown;
2754 MultiXactState->offsetStopLimit = offsetStopLimit;
2755 LWLockRelease(MultiXactGenLock);
2756
2757 /*
2758 * Do we need an emergency autovacuum? If we're not sure, assume yes.
2759 */
2760 return !oldestOffsetKnown ||
2761 (nextOffset - oldestOffset > MULTIXACT_MEMBER_SAFE_THRESHOLD);
2762}
#define LOG
Definition: elog.h:31
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition: multixact.c:2822

References Assert(), DEBUG1, ereport, errmsg(), errmsg_internal(), find_multixact_start(), MultiXactStateData::finishedStartup, LOG, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MULTIXACT_MEMBER_SAFE_THRESHOLD, MULTIXACT_MEMBERS_PER_PAGE, MultiXactState, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::offsetStopLimit, MultiXactStateData::oldestMultiXactId, MultiXactStateData::oldestOffset, MultiXactStateData::oldestOffsetKnown, and SLRU_PAGES_PER_SEGMENT.

Referenced by SetMultiXactIdLimit().

◆ SlruScanDirCbFindEarliest()

static bool SlruScanDirCbFindEarliest ( SlruCtl  ctl,
char *  filename,
int64  segpage,
void *  data 
)
static

Definition at line 2973 of file multixact.c.

2974{
2975 mxtruncinfo *trunc = (mxtruncinfo *) data;
2976
2977 if (trunc->earliestExistingPage == -1 ||
2978 ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
2979 {
2980 trunc->earliestExistingPage = segpage;
2981 }
2982
2983 return false; /* keep going */
2984}
const void * data
tree ctl
Definition: radixtree.h:1838
int64 earliestExistingPage
Definition: multixact.c:2965

References ctl, data, and mxtruncinfo::earliestExistingPage.

Referenced by TruncateMultiXact().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2083 of file multixact.c.

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

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

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

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

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

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

◆ WriteMTruncateXlogRec()

static void WriteMTruncateXlogRec ( Oid  oldestMultiDB,
MultiXactId  startTruncOff,
MultiXactId  endTruncOff,
MultiXactOffset  startTruncMemb,
MultiXactOffset  endTruncMemb 
)
static

Definition at line 3305 of file multixact.c.

3308{
3309 XLogRecPtr recptr;
3311
3312 xlrec.oldestMultiDB = oldestMultiDB;
3313
3314 xlrec.startTruncOff = startTruncOff;
3315 xlrec.endTruncOff = endTruncOff;
3316
3317 xlrec.startTruncMemb = startTruncMemb;
3318 xlrec.endTruncMemb = endTruncMemb;
3319
3322 recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3323 XLogFlush(recptr);
3324}
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2780
uint64 XLogRecPtr
Definition: xlogdefs.h:21

References xl_multixact_truncate::endTruncMemb, xl_multixact_truncate::endTruncOff, xl_multixact_truncate::oldestMultiDB, SizeOfMultiXactTruncate, xl_multixact_truncate::startTruncMemb, xl_multixact_truncate::startTruncOff, XLOG_MULTIXACT_TRUNCATE_ID, XLogBeginInsert(), XLogFlush(), XLogInsert(), and XLogRegisterData().

Referenced by TruncateMultiXact().

Variable Documentation

◆ MultiXactMemberCtlData

SlruCtlData MultiXactMemberCtlData
static

Definition at line 226 of file multixact.c.

◆ MultiXactOffsetCtlData

SlruCtlData MultiXactOffsetCtlData
static

Definition at line 225 of file multixact.c.

◆ MultiXactState

◆ MXactCache

◆ MXactContext

MemoryContext MXactContext = NULL
static

Definition at line 368 of file multixact.c.

Referenced by AtEOXact_MultiXact(), mXactCachePut(), and PostPrepare_MultiXact().

◆ OldestMemberMXactId

◆ OldestVisibleMXactId