PostgreSQL Source Code  git master
multixact.c File Reference
#include "postgres.h"
#include "access/multixact.h"
#include "access/slru.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "commands/dbcommands.h"
#include "funcapi.h"
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/fmgrprotos.h"
#include "utils/guc_hooks.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 MultiXactIdToOffsetPage(xid)    ((xid) / (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)
 
#define MultiXactIdToOffsetEntry(xid)    ((xid) % (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)
 
#define MultiXactIdToOffsetSegment(xid)   (MultiXactIdToOffsetPage(xid) / SLRU_PAGES_PER_SEGMENT)
 
#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 MXOffsetToMemberPage(xid)   ((xid) / (TransactionId) MULTIXACT_MEMBERS_PER_PAGE)
 
#define MXOffsetToMemberSegment(xid)   (MXOffsetToMemberPage(xid) / SLRU_PAGES_PER_SEGMENT)
 
#define MXOffsetToFlagsOffset(xid)
 
#define MXOffsetToFlagsBitShift(xid)
 
#define MXOffsetToMemberOffset(xid)
 
#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)
 
#define MULTIXACT_MEMBER_DANGER_THRESHOLD    (MaxMultiXactOffset - MaxMultiXactOffset / 4)
 
#define PreviousMultiXactId(xid)    ((xid) == FirstMultiXactId ? MaxMultiXactId : (xid) - 1)
 
#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 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 char * mxstatus_to_string (MultiXactStatus status)
 
static int ZeroMultiXactOffsetPage (int64 pageno, bool writeXlog)
 
static int ZeroMultiXactMemberPage (int64 pageno, bool writeXlog)
 
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 WriteMZeroPageXlogRec (int64 pageno, uint8 info)
 
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 * mxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)
 
void AtEOXact_MultiXact (void)
 
void AtPrepare_MultiXact (void)
 
void PostPrepare_MultiXact (TransactionId xid)
 
void multixact_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postcommit (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postabort (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
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)
 
static bool ReadMultiXactCounts (uint32 *multixacts, MultiXactOffset *members)
 
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)
 
Datum pg_get_multixact_members (PG_FUNCTION_ARGS)
 
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 339 of file multixact.c.

◆ debug_elog3

#define debug_elog3 (   a,
  b,
  c 
)

Definition at line 340 of file multixact.c.

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

Definition at line 341 of file multixact.c.

◆ debug_elog5

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

Definition at line 342 of file multixact.c.

◆ debug_elog6

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

Definition at line 343 of file multixact.c.

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

Definition at line 328 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 155 of file multixact.c.

◆ MaxOldestSlot

#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)

Definition at line 295 of file multixact.c.

◆ MULTIXACT_FLAGBYTES_PER_GROUP

#define MULTIXACT_FLAGBYTES_PER_GROUP   4

Definition at line 135 of file multixact.c.

◆ MULTIXACT_MEMBER_DANGER_THRESHOLD

#define MULTIXACT_MEMBER_DANGER_THRESHOLD    (MaxMultiXactOffset - MaxMultiXactOffset / 4)

Definition at line 178 of file multixact.c.

◆ MULTIXACT_MEMBER_SAFE_THRESHOLD

#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)

Definition at line 177 of file multixact.c.

◆ MULTIXACT_MEMBERGROUP_SIZE

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

Definition at line 139 of file multixact.c.

◆ MULTIXACT_MEMBERGROUPS_PER_PAGE

#define MULTIXACT_MEMBERGROUPS_PER_PAGE   (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)

Definition at line 141 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 136 of file multixact.c.

◆ MULTIXACT_MEMBERS_PER_PAGE

#define MULTIXACT_MEMBERS_PER_PAGE    (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)

Definition at line 142 of file multixact.c.

◆ MULTIXACT_OFFSETS_PER_PAGE

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))

Definition at line 109 of file multixact.c.

◆ MultiXactIdToOffsetEntry

#define MultiXactIdToOffsetEntry (   xid)     ((xid) % (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)

Definition at line 113 of file multixact.c.

◆ MultiXactIdToOffsetPage

#define MultiXactIdToOffsetPage (   xid)     ((xid) / (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)

Definition at line 111 of file multixact.c.

◆ MultiXactIdToOffsetSegment

#define MultiXactIdToOffsetSegment (   xid)    (MultiXactIdToOffsetPage(xid) / SLRU_PAGES_PER_SEGMENT)

Definition at line 115 of file multixact.c.

◆ MultiXactMemberCtl

#define MultiXactMemberCtl   (&MultiXactMemberCtlData)

Definition at line 191 of file multixact.c.

◆ MultiXactOffsetCtl

#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)

Definition at line 190 of file multixact.c.

◆ MXACT_MEMBER_BITS_PER_XACT

#define MXACT_MEMBER_BITS_PER_XACT   8

Definition at line 130 of file multixact.c.

◆ MXACT_MEMBER_FLAGS_PER_BYTE

#define MXACT_MEMBER_FLAGS_PER_BYTE   1

Definition at line 131 of file multixact.c.

◆ MXACT_MEMBER_XACT_BITMASK

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

Definition at line 132 of file multixact.c.

◆ MXOffsetToFlagsBitShift

#define MXOffsetToFlagsBitShift (   xid)
Value:
uint32 TransactionId
Definition: c.h:652
#define MXACT_MEMBER_BITS_PER_XACT
Definition: multixact.c:130
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP
Definition: multixact.c:136

Definition at line 167 of file multixact.c.

◆ MXOffsetToFlagsOffset

#define MXOffsetToFlagsOffset (   xid)
Value:

Definition at line 163 of file multixact.c.

◆ MXOffsetToMemberOffset

#define MXOffsetToMemberOffset (   xid)
Value:
#define MULTIXACT_FLAGBYTES_PER_GROUP
Definition: multixact.c:135
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163

Definition at line 172 of file multixact.c.

◆ MXOffsetToMemberPage

#define MXOffsetToMemberPage (   xid)    ((xid) / (TransactionId) MULTIXACT_MEMBERS_PER_PAGE)

Definition at line 159 of file multixact.c.

◆ MXOffsetToMemberSegment

#define MXOffsetToMemberSegment (   xid)    (MXOffsetToMemberPage(xid) / SLRU_PAGES_PER_SEGMENT)

Definition at line 160 of file multixact.c.

◆ OFFSET_WARN_SEGMENTS

#define OFFSET_WARN_SEGMENTS   20

◆ PreviousMultiXactId

#define PreviousMultiXactId (   xid)     ((xid) == FirstMultiXactId ? MaxMultiXactId : (xid) - 1)

Definition at line 181 of file multixact.c.

◆ SHARED_MULTIXACT_STATE_SIZE

#define SHARED_MULTIXACT_STATE_SIZE
Value:
add_size(offsetof(MultiXactStateData, perBackendXactIds), \
TransactionId MultiXactId
Definition: c.h:662
#define MaxOldestSlot
Definition: multixact.c:295
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 1759 of file multixact.c.

1760 {
1761  /*
1762  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1763  * which should only be valid while within a transaction.
1764  *
1765  * We assume that storing a MultiXactId is atomic and so we need not take
1766  * MultiXactGenLock to do this.
1767  */
1770 
1771  /*
1772  * Discard the local MultiXactId cache. Since MXactContext was created as
1773  * a child of TopTransactionContext, we needn't delete it explicitly.
1774  */
1775  MXactContext = NULL;
1777 }
ProcNumber MyProcNumber
Definition: globals.c:87
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:330
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:300
static dclist_head MXactCache
Definition: multixact.c:329
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:299
#define InvalidMultiXactId
Definition: multixact.h:24

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

Referenced by AbortTransaction(), and CommitTransaction().

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1787 of file multixact.c.

1788 {
1789  MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
1790 
1791  if (MultiXactIdIsValid(myOldestMember))
1793  &myOldestMember, sizeof(MultiXactId));
1794 }
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1280
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27

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

Referenced by PrepareTransaction().

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1985 of file multixact.c.

1986 {
1987  int slotno;
1988  LWLock *lock;
1989 
1991  LWLockAcquire(lock, LW_EXCLUSIVE);
1992 
1993  /* Create and zero the first page of the offsets log */
1994  slotno = ZeroMultiXactOffsetPage(0, false);
1995 
1996  /* Make sure it's written out */
1998  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1999 
2000  LWLockRelease(lock);
2001 
2003  LWLockAcquire(lock, LW_EXCLUSIVE);
2004 
2005  /* Create and zero the first page of the members log */
2006  slotno = ZeroMultiXactMemberPage(0, false);
2007 
2008  /* Make sure it's written out */
2010  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
2011 
2012  LWLockRelease(lock);
2013 }
#define Assert(condition)
Definition: c.h:858
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2041
#define MultiXactMemberCtl
Definition: multixact.c:191
#define MultiXactOffsetCtl
Definition: multixact.c:190
static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2025
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:714
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:179
Definition: lwlock.h:42

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

Referenced by BootStrapXLOG().

◆ check_multixact_member_buffers()

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

Definition at line 1974 of file multixact.c.

1975 {
1976  return check_slru_buffers("multixact_member_buffers", newval);
1977 }
#define newval
bool check_slru_buffers(const char *name, int *newval)
Definition: slru.c:340

References check_slru_buffers(), and newval.

◆ check_multixact_offset_buffers()

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

Definition at line 1965 of file multixact.c.

1966 {
1967  return check_slru_buffers("multixact_offset_buffers", newval);
1968 }

References check_slru_buffers(), and newval.

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2255 of file multixact.c.

2256 {
2257  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2258 
2259  /*
2260  * Write dirty MultiXact pages to disk. This may result in sync requests
2261  * queued for later handling by ProcessSyncRequests(), as part of the
2262  * checkpoint.
2263  */
2266 
2267  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2268 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1304

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ ExtendMultiXactMember()

static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2536 of file multixact.c.

2537 {
2538  /*
2539  * It's possible that the members span more than one page of the members
2540  * file, so we loop to ensure we consider each page. The coding is not
2541  * optimal if the members span several pages, but that seems unusual
2542  * enough to not worry much about.
2543  */
2544  while (nmembers > 0)
2545  {
2546  int flagsoff;
2547  int flagsbit;
2549 
2550  /*
2551  * Only zero when at first entry of a page.
2552  */
2553  flagsoff = MXOffsetToFlagsOffset(offset);
2554  flagsbit = MXOffsetToFlagsBitShift(offset);
2555  if (flagsoff == 0 && flagsbit == 0)
2556  {
2557  int64 pageno;
2558  LWLock *lock;
2559 
2560  pageno = MXOffsetToMemberPage(offset);
2561  lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
2562 
2563  LWLockAcquire(lock, LW_EXCLUSIVE);
2564 
2565  /* Zero the page and make an XLOG entry about it */
2566  ZeroMultiXactMemberPage(pageno, true);
2567 
2568  LWLockRelease(lock);
2569  }
2570 
2571  /*
2572  * Compute the number of items till end of current page. Careful: if
2573  * addition of unsigned ints wraps around, we're at the last page of
2574  * the last segment; since that page holds a different number of items
2575  * than other pages, we need to do it differently.
2576  */
2577  if (offset + MAX_MEMBERS_IN_LAST_MEMBERS_PAGE < offset)
2578  {
2579  /*
2580  * This is the last page of the last segment; we can compute the
2581  * number of items left to allocate in it without modulo
2582  * arithmetic.
2583  */
2584  difference = MaxMultiXactOffset - offset + 1;
2585  }
2586  else
2588 
2589  /*
2590  * Advance to next page, taking care to properly handle the wraparound
2591  * case. OK if nmembers goes negative.
2592  */
2593  nmembers -= difference;
2594  offset += difference;
2595  }
2596 }
unsigned int uint32
Definition: c.h:506
Datum difference(PG_FUNCTION_ARGS)
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
#define MXOffsetToFlagsBitShift(xid)
Definition: multixact.c:167
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE
Definition: multixact.c:155
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:142
#define MaxMultiXactOffset
Definition: multixact.h:30

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

Referenced by GetNewMultiXactId().

◆ ExtendMultiXactOffset()

static void ExtendMultiXactOffset ( MultiXactId  multi)
static

Definition at line 2504 of file multixact.c.

2505 {
2506  int64 pageno;
2507  LWLock *lock;
2508 
2509  /*
2510  * No work except at first MultiXactId of a page. But beware: just after
2511  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2512  */
2513  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2514  multi != FirstMultiXactId)
2515  return;
2516 
2517  pageno = MultiXactIdToOffsetPage(multi);
2518  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2519 
2520  LWLockAcquire(lock, LW_EXCLUSIVE);
2521 
2522  /* Zero the page and make an XLOG entry about it */
2523  ZeroMultiXactOffsetPage(pageno, true);
2524 
2525  LWLockRelease(lock);
2526 }
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
#define FirstMultiXactId
Definition: multixact.h:25

References FirstMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactOffsetCtl, SimpleLruGetBankLock(), and ZeroMultiXactOffsetPage().

Referenced by GetNewMultiXactId().

◆ find_multixact_start()

static bool find_multixact_start ( MultiXactId  multi,
MultiXactOffset result 
)
static

Definition at line 2839 of file multixact.c.

2840 {
2841  MultiXactOffset offset;
2842  int64 pageno;
2843  int entryno;
2844  int slotno;
2845  MultiXactOffset *offptr;
2846 
2848 
2849  pageno = MultiXactIdToOffsetPage(multi);
2850  entryno = MultiXactIdToOffsetEntry(multi);
2851 
2852  /*
2853  * Write out dirty data, so PhysicalPageExists can work correctly.
2854  */
2857 
2859  return false;
2860 
2861  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2862  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2863  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2864  offptr += entryno;
2865  offset = *offptr;
2867 
2868  *result = offset;
2869  return true;
2870 }
uint32 MultiXactOffset
Definition: c.h:664
static MultiXactStateData * MultiXactState
Definition: multixact.c:298
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:590
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int64 pageno)
Definition: slru.c:728

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

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

◆ GetNewMultiXactId()

static MultiXactId GetNewMultiXactId ( int  nmembers,
MultiXactOffset offset 
)
static

Definition at line 985 of file multixact.c.

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

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

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

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

2070 {
2071  int64 pageno;
2072  LWLock *lock;
2073 
2075  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2076 
2077  LWLockAcquire(lock, LW_EXCLUSIVE);
2078 
2080  {
2081  int slotno;
2082 
2083  /*
2084  * Fortunately for us, SimpleLruWritePage is already prepared to deal
2085  * with creating a new segment file even if the page we're writing is
2086  * not the first in it, so this is enough.
2087  */
2088  slotno = ZeroMultiXactOffsetPage(pageno, false);
2090  }
2091 
2092  LWLockRelease(lock);
2093 }

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

Referenced by MultiXactSetNextMXact().

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 3337 of file multixact.c.

3338 {
3339  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3340 
3341  /* Backup blocks are not used in multixact records */
3342  Assert(!XLogRecHasAnyBlockRefs(record));
3343 
3344  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3345  {
3346  int64 pageno;
3347  int slotno;
3348  LWLock *lock;
3349 
3350  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3351 
3352  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
3353  LWLockAcquire(lock, LW_EXCLUSIVE);
3354 
3355  slotno = ZeroMultiXactOffsetPage(pageno, false);
3357  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3358 
3359  LWLockRelease(lock);
3360  }
3361  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3362  {
3363  int64 pageno;
3364  int slotno;
3365  LWLock *lock;
3366 
3367  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3368 
3369  lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
3370  LWLockAcquire(lock, LW_EXCLUSIVE);
3371 
3372  slotno = ZeroMultiXactMemberPage(pageno, false);
3374  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3375 
3376  LWLockRelease(lock);
3377  }
3378  else if (info == XLOG_MULTIXACT_CREATE_ID)
3379  {
3380  xl_multixact_create *xlrec =
3381  (xl_multixact_create *) XLogRecGetData(record);
3382  TransactionId max_xid;
3383  int i;
3384 
3385  /* Store the data back into the SLRU files */
3386  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3387  xlrec->members);
3388 
3389  /* Make sure nextMXact/nextOffset are beyond what this record has */
3390  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3391  xlrec->moff + xlrec->nmembers);
3392 
3393  /*
3394  * Make sure nextXid is beyond any XID mentioned in the record. This
3395  * should be unnecessary, since any XID found here ought to have other
3396  * evidence in the XLOG, but let's be safe.
3397  */
3398  max_xid = XLogRecGetXid(record);
3399  for (i = 0; i < xlrec->nmembers; i++)
3400  {
3401  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3402  max_xid = xlrec->members[i].xid;
3403  }
3404 
3406  }
3407  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3408  {
3409  xl_multixact_truncate xlrec;
3410  int64 pageno;
3411 
3412  memcpy(&xlrec, XLogRecGetData(record),
3414 
3415  elog(DEBUG1, "replaying multixact truncation: "
3416  "offsets [%u, %u), offsets segments [%x, %x), "
3417  "members [%u, %u), members segments [%x, %x)",
3418  xlrec.startTruncOff, xlrec.endTruncOff,
3421  xlrec.startTruncMemb, xlrec.endTruncMemb,
3424 
3425  /* should not be required, but more than cheap enough */
3426  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3427 
3428  /*
3429  * Advance the horizon values, so they're current at the end of
3430  * recovery.
3431  */
3432  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3433 
3435 
3436  /*
3437  * During XLOG replay, latest_page_number isn't necessarily set up
3438  * yet; insert a suitable value to bypass the sanity test in
3439  * SimpleLruTruncate.
3440  */
3441  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3442  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3443  pageno);
3445 
3446  LWLockRelease(MultiXactTruncationLock);
3447  }
3448  else
3449  elog(PANIC, "multixact_redo: unknown op code %u", info);
3450 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:480
unsigned char uint8
Definition: c.h:504
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:3020
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2992
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2313
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:869
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2462
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:69
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:68
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:71
#define SizeOfMultiXactTruncate
Definition: multixact.h:96
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:70
MultiXactId mid
Definition: multixact.h:75
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:78
MultiXactOffset moff
Definition: multixact.h:76
MultiXactId endTruncOff
Definition: multixact.h:89
MultiXactOffset startTruncMemb
Definition: multixact.h:92
MultiXactOffset endTruncMemb
Definition: multixact.h:93
MultiXactId startTruncOff
Definition: multixact.h:88
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
#define XLR_INFO_MASK
Definition: xlogrecord.h:62

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

◆ multixact_twophase_postabort()

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

Definition at line 1886 of file multixact.c.

1888 {
1889  multixact_twophase_postcommit(xid, info, recdata, len);
1890 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1871
const void size_t len

References len, and multixact_twophase_postcommit().

◆ multixact_twophase_postcommit()

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

Definition at line 1871 of file multixact.c.

1873 {
1874  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, true);
1875 
1876  Assert(len == sizeof(MultiXactId));
1877 
1878  OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1879 }
int ProcNumber
Definition: procnumber.h:24
ProcNumber TwoPhaseGetDummyProcNumber(TransactionId xid, bool lock_held)
Definition: twophase.c:903

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

Referenced by multixact_twophase_postabort().

◆ multixact_twophase_recover()

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

Definition at line 1850 of file multixact.c.

1852 {
1853  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1854  MultiXactId oldestMember;
1855 
1856  /*
1857  * Get the oldest member XID from the state file record, and set it in the
1858  * OldestMemberMXactId slot reserved for this prepared transaction.
1859  */
1860  Assert(len == sizeof(MultiXactId));
1861  oldestMember = *((MultiXactId *) recdata);
1862 
1863  OldestMemberMXactId[dummyProcNumber] = oldestMember;
1864 }

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2462 of file multixact.c.

2464 {
2465  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2467  {
2468  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2469  MultiXactState->nextMXact = minMulti;
2470  }
2471  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2472  {
2473  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2474  minMultiOffset);
2475  MultiXactState->nextOffset = minMultiOffset;
2476  }
2477  LWLockRelease(MultiXactGenLock);
2478 }
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3286

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

2488 {
2489  Assert(InRecovery);
2490 
2492  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2493 }
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 2233 of file multixact.c.

2238 {
2239  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2240  *nextMulti = MultiXactState->nextMXact;
2241  *nextMultiOffset = MultiXactState->nextOffset;
2242  *oldestMulti = MultiXactState->oldestMultiXactId;
2243  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2244  LWLockRelease(MultiXactGenLock);
2245 
2247  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2248  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2249 }
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:343

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

394 {
395  MultiXactId newMulti;
396  MultiXactMember members[2];
397 
400 
401  Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));
402 
403  /* MultiXactIdSetOldestMember() must have been called already. */
405 
406  /*
407  * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
408  * are still running. In typical usage, xid2 will be our own XID and the
409  * caller just did a check on xid1, so it'd be wasted effort.
410  */
411 
412  members[0].xid = xid1;
413  members[0].status = status1;
414  members[1].xid = xid2;
415  members[1].status = status2;
416 
417  newMulti = MultiXactIdCreateFromMembers(2, members);
418 
419  debug_elog3(DEBUG2, "Create: %s",
420  mxid_to_string(newMulti, 2, members));
421 
422  return newMulti;
423 }
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:773
#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().

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 773 of file multixact.c.

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

References DEBUG2, debug_elog2, debug_elog3, elog, END_CRIT_SECTION, ERROR, GetNewMultiXactId(), i, InvalidMultiXactId, ISUPDATE_from_mxstatus, xl_multixact_create::mid, xl_multixact_create::moff, MultiXactIdIsValid, mXactCacheGetBySet(), mXactCachePut(), mxid_to_string(), xl_multixact_create::nmembers, RecordNewMultiXact(), SizeOfMultiXactCreate, 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 445 of file multixact.c.

446 {
447  MultiXactId newMulti;
448  MultiXactMember *members;
449  MultiXactMember *newMembers;
450  int nmembers;
451  int i;
452  int j;
453 
454  Assert(MultiXactIdIsValid(multi));
456 
457  /* MultiXactIdSetOldestMember() must have been called already. */
459 
460  debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s",
461  multi, xid, mxstatus_to_string(status));
462 
463  /*
464  * Note: we don't allow for old multis here. The reason is that the only
465  * caller of this function does a check that the multixact is no longer
466  * running.
467  */
468  nmembers = GetMultiXactIdMembers(multi, &members, false, false);
469 
470  if (nmembers < 0)
471  {
472  MultiXactMember member;
473 
474  /*
475  * The MultiXactId is obsolete. This can only happen if all the
476  * MultiXactId members stop running between the caller checking and
477  * passing it to us. It would be better to return that fact to the
478  * caller, but it would complicate the API and it's unlikely to happen
479  * too often, so just deal with it by creating a singleton MultiXact.
480  */
481  member.xid = xid;
482  member.status = status;
483  newMulti = MultiXactIdCreateFromMembers(1, &member);
484 
485  debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
486  multi, newMulti);
487  return newMulti;
488  }
489 
490  /*
491  * If the TransactionId is already a member of the MultiXactId with the
492  * same status, just return the existing MultiXactId.
493  */
494  for (i = 0; i < nmembers; i++)
495  {
496  if (TransactionIdEquals(members[i].xid, xid) &&
497  (members[i].status == status))
498  {
499  debug_elog4(DEBUG2, "Expand: %u is already a member of %u",
500  xid, multi);
501  pfree(members);
502  return multi;
503  }
504  }
505 
506  /*
507  * Determine which of the members of the MultiXactId are still of
508  * interest. This is any running transaction, and also any transaction
509  * that grabbed something stronger than just a lock and was committed. (An
510  * update that aborted is of no interest here; and having more than one
511  * update Xid in a multixact would cause errors elsewhere.)
512  *
513  * Removing dead members is not just an optimization: freezing of tuples
514  * whose Xmax are multis depends on this behavior.
515  *
516  * Note we have the same race condition here as above: j could be 0 at the
517  * end of the loop.
518  */
519  newMembers = (MultiXactMember *)
520  palloc(sizeof(MultiXactMember) * (nmembers + 1));
521 
522  for (i = 0, j = 0; i < nmembers; i++)
523  {
524  if (TransactionIdIsInProgress(members[i].xid) ||
525  (ISUPDATE_from_mxstatus(members[i].status) &&
526  TransactionIdDidCommit(members[i].xid)))
527  {
528  newMembers[j].xid = members[i].xid;
529  newMembers[j++].status = members[i].status;
530  }
531  }
532 
533  newMembers[j].xid = xid;
534  newMembers[j++].status = status;
535  newMulti = MultiXactIdCreateFromMembers(j, newMembers);
536 
537  pfree(members);
538  pfree(newMembers);
539 
540  debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);
541 
542  return newMulti;
543 }
int j
Definition: isn.c:74
void pfree(void *pointer)
Definition: mcxt.c:1520
#define debug_elog5(a, b, c, d, e)
Definition: multixact.c:342
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1705
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
Definition: multixact.c:1252
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1390
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 557 of file multixact.c.

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

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

3275 {
3276  int32 diff = (int32) (multi1 - multi2);
3277 
3278  return (diff <= 0);
3279 }

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

632 {
634  {
635  MultiXactId nextMXact;
636 
637  /*
638  * You might think we don't need to acquire a lock here, since
639  * fetching and storing of TransactionIds is probably atomic, but in
640  * fact we do: suppose we pick up nextMXact and then lose the CPU for
641  * a long time. Someone else could advance nextMXact, and then
642  * another someone else could compute an OldestVisibleMXactId that
643  * would be after the value we are going to store when we get control
644  * back. Which would be wrong.
645  *
646  * Note that a shared lock is sufficient, because it's enough to stop
647  * someone from advancing nextMXact; and nobody else could be trying
648  * to write to our OldestMember entry, only reading (and we assume
649  * storing it is atomic.)
650  */
651  LWLockAcquire(MultiXactGenLock, LW_SHARED);
652 
653  /*
654  * We have to beware of the possibility that nextMXact is in the
655  * wrapped-around state. We don't fix the counter itself here, but we
656  * must be sure to store a valid value in our array entry.
657  */
658  nextMXact = MultiXactState->nextMXact;
659  if (nextMXact < FirstMultiXactId)
660  nextMXact = FirstMultiXactId;
661 
662  OldestMemberMXactId[MyProcNumber] = nextMXact;
663 
664  LWLockRelease(MultiXactGenLock);
665 
666  debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
667  MyProcNumber, nextMXact);
668  }
669 }

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

◆ MultiXactIdSetOldestVisible()

static void MultiXactIdSetOldestVisible ( void  )
static

Definition at line 688 of file multixact.c.

689 {
691  {
692  MultiXactId oldestMXact;
693  int i;
694 
695  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
696 
697  /*
698  * We have to beware of the possibility that nextMXact is in the
699  * wrapped-around state. We don't fix the counter itself here, but we
700  * must be sure to store a valid value in our array entry.
701  */
702  oldestMXact = MultiXactState->nextMXact;
703  if (oldestMXact < FirstMultiXactId)
704  oldestMXact = FirstMultiXactId;
705 
706  for (i = 0; i < MaxOldestSlot; i++)
707  {
708  MultiXactId thisoldest = OldestMemberMXactId[i];
709 
710  if (MultiXactIdIsValid(thisoldest) &&
711  MultiXactIdPrecedes(thisoldest, oldestMXact))
712  oldestMXact = thisoldest;
713  }
714 
715  OldestVisibleMXactId[MyProcNumber] = oldestMXact;
716 
717  LWLockRelease(MultiXactGenLock);
718 
719  debug_elog4(DEBUG2, "MultiXact: setting OldestVisible[%d] = %u",
720  MyProcNumber, oldestMXact);
721  }
722 }

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

Referenced by GetMultiXactIdMembers().

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2929 of file multixact.c.

2930 {
2931  MultiXactOffset members;
2932  uint32 multixacts;
2933  uint32 victim_multixacts;
2934  double fraction;
2935 
2936  /* If we can't determine member space utilization, assume the worst. */
2937  if (!ReadMultiXactCounts(&multixacts, &members))
2938  return 0;
2939 
2940  /* If member space utilization is low, no special action is required. */
2941  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2943 
2944  /*
2945  * Compute a target for relminmxid advancement. The number of multixacts
2946  * we try to eliminate from the system is based on how far we are past
2947  * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2948  */
2949  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2951  victim_multixacts = multixacts * fraction;
2952 
2953  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2954  if (victim_multixacts > multixacts)
2955  return 0;
2956  return multixacts - victim_multixacts;
2957 }
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:127
static bool ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
Definition: multixact.c:2877
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:178

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

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

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 3240 of file multixact.c.

3241 {
3242  MultiXactOffset offset1;
3243  MultiXactOffset offset2;
3244 
3245  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3246  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3247 
3248  return (MultiXactOffsetPrecedes(offset1, offset2) &&
3249  MultiXactOffsetPrecedes(offset1,
3250  offset2 + MULTIXACT_MEMBERS_PER_PAGE - 1));
3251 }

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3527 of file multixact.c.

3528 {
3529  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3530 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1813

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 3220 of file multixact.c.

3221 {
3222  MultiXactId multi1;
3223  MultiXactId multi2;
3224 
3225  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3226  multi1 += FirstMultiXactId + 1;
3227  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3228  multi2 += FirstMultiXactId + 1;
3229 
3230  return (MultiXactIdPrecedes(multi1, multi2) &&
3231  MultiXactIdPrecedes(multi1,
3232  multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
3233 }
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

◆ MultiXactOffsetPrecedes()

static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3286 of file multixact.c.

3287 {
3288  int32 diff = (int32) (offset1 - offset2);
3289 
3290  return (diff < 0);
3291 }

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3518 of file multixact.c.

3519 {
3520  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3521 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactOffsetWouldWrap()

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

Definition at line 2791 of file multixact.c.

2793 {
2794  MultiXactOffset finish;
2795 
2796  /*
2797  * Note that offset number 0 is not used (see GetMultiXactIdMembers), so
2798  * if the addition wraps around the UINT_MAX boundary, skip that value.
2799  */
2800  finish = start + distance;
2801  if (finish < start)
2802  finish++;
2803 
2804  /*-----------------------------------------------------------------------
2805  * When the boundary is numerically greater than the starting point, any
2806  * value numerically between the two is not wrapped:
2807  *
2808  * <----S----B---->
2809  * [---) = F wrapped past B (and UINT_MAX)
2810  * [---) = F not wrapped
2811  * [----] = F wrapped past B
2812  *
2813  * When the boundary is numerically less than the starting point (i.e. the
2814  * UINT_MAX wraparound occurs somewhere in between) then all values in
2815  * between are wrapped:
2816  *
2817  * <----B----S---->
2818  * [---) = F not wrapped past B (but wrapped past UINT_MAX)
2819  * [---) = F wrapped past B (and UINT_MAX)
2820  * [----] = F not wrapped
2821  *-----------------------------------------------------------------------
2822  */
2823  if (start < boundary)
2824  return finish >= boundary || finish < start;
2825  else
2826  return finish >= boundary && finish < start;
2827 }
return str start

References start.

Referenced by GetNewMultiXactId().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2279 of file multixact.c.

2281 {
2282  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2283  nextMulti, nextMultiOffset);
2284  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2285  MultiXactState->nextMXact = nextMulti;
2286  MultiXactState->nextOffset = nextMultiOffset;
2287  LWLockRelease(MultiXactGenLock);
2288 
2289  /*
2290  * During a binary upgrade, make sure that the offsets SLRU is large
2291  * enough to contain the next value that would be created.
2292  *
2293  * We need to do this pretty early during the first startup in binary
2294  * upgrade mode: before StartupMultiXact() in fact, because this routine
2295  * is called even before that by StartupXLOG(). And we can't do it
2296  * earlier than at this point, because during that first call of this
2297  * routine we determine the MultiXactState->nextMXact value that
2298  * MaybeExtendOffsetSlru needs.
2299  */
2300  if (IsBinaryUpgrade)
2302 }
bool IsBinaryUpgrade
Definition: globals.c:118
static void MaybeExtendOffsetSlru(void)
Definition: multixact.c:2069

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

1916 {
1917  bool found;
1918 
1919  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1920 
1923 
1925  "multixact_offset", multixact_offset_buffers, 0,
1926  "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1929  false);
1932  "multixact_member", multixact_member_buffers, 0,
1933  "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1936  false);
1937  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1938 
1939  /* Initialize our shared state struct */
1940  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1942  &found);
1943  if (!IsUnderPostmaster)
1944  {
1945  Assert(!found);
1946 
1947  /* Make sure we zero out the per-backend state */
1950  }
1951  else
1952  Assert(found);
1953 
1954  /*
1955  * Set up array pointers.
1956  */
1959 }
#define MemSet(start, val, len)
Definition: c.h:1020
void ConditionVariableInit(ConditionVariable *cv)
int multixact_offset_buffers
Definition: globals.c:164
int multixact_member_buffers
Definition: globals.c:163
@ LWTRANCHE_MULTIXACTOFFSET_SLRU
Definition: lwlock.h:212
@ LWTRANCHE_MULTIXACTMEMBER_SLRU
Definition: lwlock.h:211
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:183
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:182
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3240
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3220
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:237
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:203
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:289
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40

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

Referenced by CreateOrAttachShmemStructs().

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1898 of file multixact.c.

1899 {
1900  Size size;
1901 
1902  /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1903 #define SHARED_MULTIXACT_STATE_SIZE \
1904  add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1905  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1906 
1910 
1911  return size;
1912 }
size_t Size
Definition: c.h:605
static pg_noinline void Size size
Definition: slab.c:607
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:184

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

Referenced by CalculateShmemSize().

◆ mXactCacheGetById()

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

Definition at line 1613 of file multixact.c.

1614 {
1615  dlist_iter iter;
1616 
1617  debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1618 
1619  dclist_foreach(iter, &MXactCache)
1620  {
1622  iter.cur);
1623 
1624  if (entry->multi == multi)
1625  {
1626  MultiXactMember *ptr;
1627  Size size;
1628 
1629  size = sizeof(MultiXactMember) * entry->nmembers;
1630  ptr = (MultiXactMember *) palloc(size);
1631 
1632  memcpy(ptr, entry->members, size);
1633 
1634  debug_elog3(DEBUG2, "CacheGet: found %s",
1635  mxid_to_string(multi,
1636  entry->nmembers,
1637  entry->members));
1638 
1639  /*
1640  * Note we modify the list while not using a modifiable iterator.
1641  * This is acceptable only because we exit the iteration
1642  * immediately afterwards.
1643  */
1645 
1646  *members = ptr;
1647  return entry->nmembers;
1648  }
1649  }
1650 
1651  debug_elog2(DEBUG2, "CacheGet: not found");
1652  return -1;
1653 }
#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:322
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:325

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

Referenced by GetMultiXactIdMembers().

◆ mXactCacheGetBySet()

static MultiXactId mXactCacheGetBySet ( int  nmembers,
MultiXactMember members 
)
static

Definition at line 1570 of file multixact.c.

1571 {
1572  dlist_iter iter;
1573 
1574  debug_elog3(DEBUG2, "CacheGet: looking for %s",
1575  mxid_to_string(InvalidMultiXactId, nmembers, members));
1576 
1577  /* sort the array so comparison is easy */
1578  qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1579 
1580  dclist_foreach(iter, &MXactCache)
1581  {
1583  iter.cur);
1584 
1585  if (entry->nmembers != nmembers)
1586  continue;
1587 
1588  /*
1589  * We assume the cache entries are sorted, and that the unused bits in
1590  * "status" are zeroed.
1591  */
1592  if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1593  {
1594  debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1596  return entry->multi;
1597  }
1598  }
1599 
1600  debug_elog2(DEBUG2, "CacheGet: not found :-(");
1601  return InvalidMultiXactId;
1602 }
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition: multixact.c:1540
#define qsort(a, b, c, d)
Definition: port.h:449

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

1661 {
1662  mXactCacheEnt *entry;
1663 
1664  debug_elog3(DEBUG2, "CachePut: storing %s",
1665  mxid_to_string(multi, nmembers, members));
1666 
1667  if (MXactContext == NULL)
1668  {
1669  /* The cache only lives as long as the current transaction */
1670  debug_elog2(DEBUG2, "CachePut: initializing memory context");
1672  "MultiXact cache context",
1674  }
1675 
1676  entry = (mXactCacheEnt *)
1678  offsetof(mXactCacheEnt, members) +
1679  nmembers * sizeof(MultiXactMember));
1680 
1681  entry->multi = multi;
1682  entry->nmembers = nmembers;
1683  memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1684 
1685  /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1686  qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1687 
1688  dclist_push_head(&MXactCache, &entry->node);
1690  {
1691  dlist_node *node;
1692 
1693  node = dclist_tail_node(&MXactCache);
1695 
1696  entry = dclist_container(mXactCacheEnt, node, node);
1697  debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1698  entry->multi);
1699 
1700  pfree(entry);
1701  }
1702 }
static dlist_node * dclist_tail_node(dclist_head *head)
Definition: ilist.h:920
static uint32 dclist_count(const dclist_head *head)
Definition: ilist.h:932
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
MemoryContext TopTransactionContext
Definition: mcxt.c:154
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1180
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
#define MAX_CACHE_ENTRIES
Definition: multixact.c:328
dlist_node node
Definition: multixact.c:324

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

1541 {
1542  MultiXactMember member1 = *(const MultiXactMember *) arg1;
1543  MultiXactMember member2 = *(const MultiXactMember *) arg2;
1544 
1545  if (member1.xid > member2.xid)
1546  return 1;
1547  if (member1.xid < member2.xid)
1548  return -1;
1549  if (member1.status > member2.status)
1550  return 1;
1551  if (member1.status < member2.status)
1552  return -1;
1553  return 0;
1554 }

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

1729 {
1730  static char *str = NULL;
1732  int i;
1733 
1734  if (str != NULL)
1735  pfree(str);
1736 
1737  initStringInfo(&buf);
1738 
1739  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1740  mxstatus_to_string(members[0].status));
1741 
1742  for (i = 1; i < nmembers; i++)
1743  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1744  mxstatus_to_string(members[i].status));
1745 
1746  appendStringInfoChar(&buf, ']');
1748  pfree(buf.data);
1749  return str;
1750 }
const char * str
MemoryContext TopMemoryContext
Definition: mcxt.c:149
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1682
static char * buf
Definition: pg_test_fsync.c:73
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

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

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

◆ mxstatus_to_string()

static char * mxstatus_to_string ( MultiXactStatus  status)
static

Definition at line 1705 of file multixact.c.

1706 {
1707  switch (status)
1708  {
1710  return "keysh";
1712  return "sh";
1714  return "fornokeyupd";
1716  return "forupd";
1718  return "nokeyupd";
1719  case MultiXactStatusUpdate:
1720  return "upd";
1721  default:
1722  elog(ERROR, "unrecognized multixact status %d", status);
1723  return "";
1724  }
1725 }
@ MultiXactStatusForShare
Definition: multixact.h:40
@ MultiXactStatusForNoKeyUpdate
Definition: multixact.h:41
@ MultiXactStatusNoKeyUpdate
Definition: multixact.h:44
@ MultiXactStatusUpdate
Definition: multixact.h:46
@ MultiXactStatusForUpdate
Definition: multixact.h:42
@ MultiXactStatusForKeyShare
Definition: multixact.h:39

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

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

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

3021 {
3022  /*
3023  * We step back one multixact to avoid passing a cutoff page that hasn't
3024  * been created yet in the rare case that oldestMulti would be the first
3025  * item on a page and oldestMulti == nextMulti. In that case, if we
3026  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
3027  * detection.
3028  */
3030  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
3031 }
#define PreviousMultiXactId(xid)
Definition: multixact.c:181
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition: slru.c:1390

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

Referenced by multixact_redo(), and TruncateMultiXact().

◆ pg_get_multixact_members()

Datum pg_get_multixact_members ( PG_FUNCTION_ARGS  )

Definition at line 3453 of file multixact.c.

3454 {
3455  typedef struct
3456  {
3457  MultiXactMember *members;
3458  int nmembers;
3459  int iter;
3460  } mxact;
3462  mxact *multi;
3463  FuncCallContext *funccxt;
3464 
3465  if (mxid < FirstMultiXactId)
3466  ereport(ERROR,
3467  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3468  errmsg("invalid MultiXactId: %u", mxid)));
3469 
3470  if (SRF_IS_FIRSTCALL())
3471  {
3472  MemoryContext oldcxt;
3473  TupleDesc tupdesc;
3474 
3475  funccxt = SRF_FIRSTCALL_INIT();
3476  oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3477 
3478  multi = palloc(sizeof(mxact));
3479  /* no need to allow for old values here */
3480  multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3481  false);
3482  multi->iter = 0;
3483 
3484  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3485  elog(ERROR, "return type must be a row type");
3486  funccxt->tuple_desc = tupdesc;
3487  funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3488  funccxt->user_fctx = multi;
3489 
3490  MemoryContextSwitchTo(oldcxt);
3491  }
3492 
3493  funccxt = SRF_PERCALL_SETUP();
3494  multi = (mxact *) funccxt->user_fctx;
3495 
3496  while (multi->iter < multi->nmembers)
3497  {
3498  HeapTuple tuple;
3499  char *values[2];
3500 
3501  values[0] = psprintf("%u", multi->members[multi->iter].xid);
3502  values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3503 
3504  tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3505 
3506  multi->iter++;
3507  pfree(values[0]);
3508  SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3509  }
3510 
3511  SRF_RETURN_DONE(funccxt);
3512 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2222
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2173
#define PG_GETARG_TRANSACTIONID(n)
Definition: fmgr.h:279
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
while(p+4<=pend)
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
MemoryContextSwitchTo(old_ctx)
void * user_fctx
Definition: funcapi.h:82
AttInMetadata * attinmeta
Definition: funcapi.h:91
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112

References FuncCallContext::attinmeta, BuildTupleFromCStrings(), elog, ereport, errcode(), errmsg(), ERROR, FirstMultiXactId, get_call_result_type(), GetMultiXactIdMembers(), HeapTupleGetDatum(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, mxstatus_to_string(), palloc(), pfree(), PG_GETARG_TRANSACTIONID, psprintf(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, FuncCallContext::tuple_desc, TupleDescGetAttInMetadata(), TYPEFUNC_COMPOSITE, FuncCallContext::user_fctx, values, and while().

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1801 of file multixact.c.

1802 {
1803  MultiXactId myOldestMember;
1804 
1805  /*
1806  * Transfer our OldestMemberMXactId value to the slot reserved for the
1807  * prepared transaction.
1808  */
1809  myOldestMember = OldestMemberMXactId[MyProcNumber];
1810  if (MultiXactIdIsValid(myOldestMember))
1811  {
1812  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1813 
1814  /*
1815  * Even though storing MultiXactId is atomic, acquire lock to make
1816  * sure others see both changes, not just the reset of the slot of the
1817  * current backend. Using a volatile pointer might suffice, but this
1818  * isn't a hot spot.
1819  */
1820  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1821 
1822  OldestMemberMXactId[dummyProcNumber] = myOldestMember;
1824 
1825  LWLockRelease(MultiXactGenLock);
1826  }
1827 
1828  /*
1829  * We don't need to transfer OldestVisibleMXactId value, because the
1830  * transaction is not going to be looking at any more multixacts once it's
1831  * prepared.
1832  *
1833  * We assume that storing a MultiXactId is atomic and so we need not take
1834  * MultiXactGenLock to do this.
1835  */
1837 
1838  /*
1839  * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1840  */
1841  MXactContext = NULL;
1843 }

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

Referenced by PrepareTransaction().

◆ ReadMultiXactCounts()

static bool ReadMultiXactCounts ( uint32 multixacts,
MultiXactOffset members 
)
static

Definition at line 2877 of file multixact.c.

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

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

Referenced by MultiXactMemberFreezeThreshold().

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 749 of file multixact.c.

750 {
751  LWLockAcquire(MultiXactGenLock, LW_SHARED);
754  LWLockRelease(MultiXactGenLock);
755 
756  if (*oldest < FirstMultiXactId)
757  *oldest = FirstMultiXactId;
758  if (*next < FirstMultiXactId)
760 }
static int32 next
Definition: blutils.c:221

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

Referenced by update_cached_mxid_range().

◆ ReadNextMultiXactId()

MultiXactId ReadNextMultiXactId ( void  )

Definition at line 729 of file multixact.c.

730 {
731  MultiXactId mxid;
732 
733  /* XXX we could presumably do this without a lock. */
734  LWLockAcquire(MultiXactGenLock, LW_SHARED);
735  mxid = MultiXactState->nextMXact;
736  LWLockRelease(MultiXactGenLock);
737 
738  if (mxid < FirstMultiXactId)
739  mxid = FirstMultiXactId;
740 
741  return mxid;
742 }

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

871 {
872  int64 pageno;
873  int64 prev_pageno;
874  int entryno;
875  int slotno;
876  MultiXactOffset *offptr;
877  int i;
878  LWLock *lock;
879  LWLock *prevlock = NULL;
880 
881  pageno = MultiXactIdToOffsetPage(multi);
882  entryno = MultiXactIdToOffsetEntry(multi);
883 
886 
887  /*
888  * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
889  * to complain about if there's any I/O error. This is kinda bogus, but
890  * since the errors will always give the full pathname, it should be clear
891  * enough that a MultiXactId is really involved. Perhaps someday we'll
892  * take the trouble to generalize the slru.c error reporting code.
893  */
894  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
895  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
896  offptr += entryno;
897 
898  *offptr = offset;
899 
900  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
901 
902  /* Release MultiXactOffset SLRU lock. */
903  LWLockRelease(lock);
904 
905  /*
906  * If anybody was waiting to know the offset of this multixact ID we just
907  * wrote, they can read it now, so wake them up.
908  */
910 
911  prev_pageno = -1;
912 
913  for (i = 0; i < nmembers; i++, offset++)
914  {
915  TransactionId *memberptr;
916  uint32 *flagsptr;
917  uint32 flagsval;
918  int bshift;
919  int flagsoff;
920  int memberoff;
921 
922  Assert(members[i].status <= MultiXactStatusUpdate);
923 
924  pageno = MXOffsetToMemberPage(offset);
925  memberoff = MXOffsetToMemberOffset(offset);
926  flagsoff = MXOffsetToFlagsOffset(offset);
927  bshift = MXOffsetToFlagsBitShift(offset);
928 
929  if (pageno != prev_pageno)
930  {
931  /*
932  * MultiXactMember SLRU page is changed so check if this new page
933  * fall into the different SLRU bank then release the old bank's
934  * lock and acquire lock on the new bank.
935  */
937  if (lock != prevlock)
938  {
939  if (prevlock != NULL)
940  LWLockRelease(prevlock);
941 
943  prevlock = lock;
944  }
945  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
946  prev_pageno = pageno;
947  }
948 
949  memberptr = (TransactionId *)
950  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
951 
952  *memberptr = members[i].xid;
953 
954  flagsptr = (uint32 *)
955  (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
956 
957  flagsval = *flagsptr;
958  flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
959  flagsval |= (members[i].status << bshift);
960  *flagsptr = flagsval;
961 
962  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
963  }
964 
965  if (prevlock != NULL)
966  LWLockRelease(prevlock);
967 }
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 2313 of file multixact.c.

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

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

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

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

2970 {
2971  mxtruncinfo *trunc = (mxtruncinfo *) data;
2972 
2973  if (trunc->earliestExistingPage == -1 ||
2974  ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
2975  {
2976  trunc->earliestExistingPage = segpage;
2977  }
2978 
2979  return false; /* keep going */
2980 }
const void * data
tree ctl
Definition: radixtree.h:1851
int64 earliestExistingPage
Definition: multixact.c:2961

References ctl, data, and mxtruncinfo::earliestExistingPage.

Referenced by TruncateMultiXact().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2104 of file multixact.c.

2105 {
2108  int64 pageno;
2109 
2110  /*
2111  * Initialize offset's idea of the latest page number.
2112  */
2113  pageno = MultiXactIdToOffsetPage(multi);
2114  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2115  pageno);
2116 
2117  /*
2118  * Initialize member's idea of the latest page number.
2119  */
2120  pageno = MXOffsetToMemberPage(offset);
2121  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2122  pageno);
2123 }

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

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

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

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

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

3315 {
3316  XLogRecPtr recptr;
3317  xl_multixact_truncate xlrec;
3318 
3319  xlrec.oldestMultiDB = oldestMultiDB;
3320 
3321  xlrec.startTruncOff = startTruncOff;
3322  xlrec.endTruncOff = endTruncOff;
3323 
3324  xlrec.startTruncMemb = startTruncMemb;
3325  xlrec.endTruncMemb = endTruncMemb;
3326 
3327  XLogBeginInsert();
3328  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3329  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3330  XLogFlush(recptr);
3331 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2791
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().

◆ WriteMZeroPageXlogRec()

static void WriteMZeroPageXlogRec ( int64  pageno,
uint8  info 
)
static

Definition at line 3298 of file multixact.c.

3299 {
3300  XLogBeginInsert();
3301  XLogRegisterData((char *) (&pageno), sizeof(pageno));
3302  (void) XLogInsert(RM_MULTIXACT_ID, info);
3303 }

References XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

◆ ZeroMultiXactMemberPage()

static int ZeroMultiXactMemberPage ( int64  pageno,
bool  writeXlog 
)
static

Definition at line 2041 of file multixact.c.

2042 {
2043  int slotno;
2044 
2045  slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
2046 
2047  if (writeXlog)
2049 
2050  return slotno;
2051 }
static void WriteMZeroPageXlogRec(int64 pageno, uint8 info)
Definition: multixact.c:3298
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:360

References MultiXactMemberCtl, SimpleLruZeroPage(), WriteMZeroPageXlogRec(), and XLOG_MULTIXACT_ZERO_MEM_PAGE.

Referenced by BootStrapMultiXact(), ExtendMultiXactMember(), and multixact_redo().

◆ ZeroMultiXactOffsetPage()

static int ZeroMultiXactOffsetPage ( int64  pageno,
bool  writeXlog 
)
static

Definition at line 2025 of file multixact.c.

2026 {
2027  int slotno;
2028 
2029  slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
2030 
2031  if (writeXlog)
2033 
2034  return slotno;
2035 }

References MultiXactOffsetCtl, SimpleLruZeroPage(), WriteMZeroPageXlogRec(), and XLOG_MULTIXACT_ZERO_OFF_PAGE.

Referenced by BootStrapMultiXact(), ExtendMultiXactOffset(), MaybeExtendOffsetSlru(), and multixact_redo().

Variable Documentation

◆ MultiXactMemberCtlData

SlruCtlData MultiXactMemberCtlData
static

Definition at line 188 of file multixact.c.

◆ MultiXactOffsetCtlData

SlruCtlData MultiXactOffsetCtlData
static

Definition at line 187 of file multixact.c.

◆ MultiXactState

◆ MXactCache

◆ MXactContext

MemoryContext MXactContext = NULL
static

Definition at line 330 of file multixact.c.

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

◆ OldestMemberMXactId

◆ OldestVisibleMXactId