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

◆ debug_elog3

#define debug_elog3 (   a,
  b,
  c 
)

Definition at line 333 of file multixact.c.

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

Definition at line 334 of file multixact.c.

◆ debug_elog5

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

Definition at line 335 of file multixact.c.

◆ debug_elog6

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

Definition at line 336 of file multixact.c.

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

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

◆ MaxOldestSlot

#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)

Definition at line 288 of file multixact.c.

◆ MULTIXACT_FLAGBYTES_PER_GROUP

#define MULTIXACT_FLAGBYTES_PER_GROUP   4

Definition at line 134 of file multixact.c.

◆ MULTIXACT_MEMBER_DANGER_THRESHOLD

#define MULTIXACT_MEMBER_DANGER_THRESHOLD    (MaxMultiXactOffset - MaxMultiXactOffset / 4)

Definition at line 177 of file multixact.c.

◆ MULTIXACT_MEMBER_SAFE_THRESHOLD

#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)

Definition at line 176 of file multixact.c.

◆ MULTIXACT_MEMBERGROUP_SIZE

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

Definition at line 138 of file multixact.c.

◆ MULTIXACT_MEMBERGROUPS_PER_PAGE

#define MULTIXACT_MEMBERGROUPS_PER_PAGE   (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)

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

◆ MULTIXACT_MEMBERS_PER_PAGE

#define MULTIXACT_MEMBERS_PER_PAGE    (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)

Definition at line 141 of file multixact.c.

◆ MULTIXACT_OFFSETS_PER_PAGE

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))

Definition at line 108 of file multixact.c.

◆ MultiXactIdToOffsetEntry

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

Definition at line 112 of file multixact.c.

◆ MultiXactIdToOffsetPage

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

Definition at line 110 of file multixact.c.

◆ MultiXactIdToOffsetSegment

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

Definition at line 114 of file multixact.c.

◆ MultiXactMemberCtl

#define MultiXactMemberCtl   (&MultiXactMemberCtlData)

Definition at line 190 of file multixact.c.

◆ MultiXactOffsetCtl

#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)

Definition at line 189 of file multixact.c.

◆ MXACT_MEMBER_BITS_PER_XACT

#define MXACT_MEMBER_BITS_PER_XACT   8

Definition at line 129 of file multixact.c.

◆ MXACT_MEMBER_FLAGS_PER_BYTE

#define MXACT_MEMBER_FLAGS_PER_BYTE   1

Definition at line 130 of file multixact.c.

◆ MXACT_MEMBER_XACT_BITMASK

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

Definition at line 131 of file multixact.c.

◆ MXOffsetToFlagsBitShift

#define MXOffsetToFlagsBitShift (   xid)
Value:
uint32 TransactionId
Definition: c.h:639
#define MXACT_MEMBER_BITS_PER_XACT
Definition: multixact.c:129
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP
Definition: multixact.c:135

Definition at line 166 of file multixact.c.

◆ MXOffsetToFlagsOffset

#define MXOffsetToFlagsOffset (   xid)
Value:

Definition at line 162 of file multixact.c.

◆ MXOffsetToMemberOffset

#define MXOffsetToMemberOffset (   xid)
Value:
#define MULTIXACT_FLAGBYTES_PER_GROUP
Definition: multixact.c:134
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:162

Definition at line 171 of file multixact.c.

◆ MXOffsetToMemberPage

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

Definition at line 158 of file multixact.c.

◆ MXOffsetToMemberSegment

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

Definition at line 159 of file multixact.c.

◆ OFFSET_WARN_SEGMENTS

#define OFFSET_WARN_SEGMENTS   20

◆ PreviousMultiXactId

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

Definition at line 180 of file multixact.c.

◆ SHARED_MULTIXACT_STATE_SIZE

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

1735 {
1736  /*
1737  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1738  * which should only be valid while within a transaction.
1739  *
1740  * We assume that storing a MultiXactId is atomic and so we need not take
1741  * MultiXactGenLock to do this.
1742  */
1745 
1746  /*
1747  * Discard the local MultiXactId cache. Since MXactContext was created as
1748  * a child of TopTransactionContext, we needn't delete it explicitly.
1749  */
1750  MXactContext = NULL;
1752 }
ProcNumber MyProcNumber
Definition: globals.c:87
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:323
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
static dclist_head MXactCache
Definition: multixact.c:322
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
#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 1762 of file multixact.c.

1763 {
1764  MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
1765 
1766  if (MultiXactIdIsValid(myOldestMember))
1768  &myOldestMember, sizeof(MultiXactId));
1769 }
#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 1959 of file multixact.c.

1960 {
1961  int slotno;
1962  LWLock *lock;
1963 
1965  LWLockAcquire(lock, LW_EXCLUSIVE);
1966 
1967  /* Create and zero the first page of the offsets log */
1968  slotno = ZeroMultiXactOffsetPage(0, false);
1969 
1970  /* Make sure it's written out */
1972  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1973 
1974  LWLockRelease(lock);
1975 
1977  LWLockAcquire(lock, LW_EXCLUSIVE);
1978 
1979  /* Create and zero the first page of the members log */
1980  slotno = ZeroMultiXactMemberPage(0, false);
1981 
1982  /* Make sure it's written out */
1984  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1985 
1986  LWLockRelease(lock);
1987 }
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1172
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1785
@ LW_EXCLUSIVE
Definition: lwlock.h:116
static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2015
#define MultiXactMemberCtl
Definition: multixact.c:190
#define MultiXactOffsetCtl
Definition: multixact.c:189
static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
Definition: multixact.c:1999
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:715
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:179
Definition: lwlock.h:41

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

1949 {
1950  return check_slru_buffers("multixact_member_buffers", newval);
1951 }
#define newval
bool check_slru_buffers(const char *name, int *newval)
Definition: slru.c:341

References check_slru_buffers(), and newval.

◆ check_multixact_offset_buffers()

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

Definition at line 1939 of file multixact.c.

1940 {
1941  return check_slru_buffers("multixact_offset_buffers", newval);
1942 }

References check_slru_buffers(), and newval.

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2229 of file multixact.c.

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

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ ExtendMultiXactMember()

static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2510 of file multixact.c.

2511 {
2512  /*
2513  * It's possible that the members span more than one page of the members
2514  * file, so we loop to ensure we consider each page. The coding is not
2515  * optimal if the members span several pages, but that seems unusual
2516  * enough to not worry much about.
2517  */
2518  while (nmembers > 0)
2519  {
2520  int flagsoff;
2521  int flagsbit;
2523 
2524  /*
2525  * Only zero when at first entry of a page.
2526  */
2527  flagsoff = MXOffsetToFlagsOffset(offset);
2528  flagsbit = MXOffsetToFlagsBitShift(offset);
2529  if (flagsoff == 0 && flagsbit == 0)
2530  {
2531  int64 pageno;
2532  LWLock *lock;
2533 
2534  pageno = MXOffsetToMemberPage(offset);
2535  lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
2536 
2537  LWLockAcquire(lock, LW_EXCLUSIVE);
2538 
2539  /* Zero the page and make an XLOG entry about it */
2540  ZeroMultiXactMemberPage(pageno, true);
2541 
2542  LWLockRelease(lock);
2543  }
2544 
2545  /*
2546  * Compute the number of items till end of current page. Careful: if
2547  * addition of unsigned ints wraps around, we're at the last page of
2548  * the last segment; since that page holds a different number of items
2549  * than other pages, we need to do it differently.
2550  */
2551  if (offset + MAX_MEMBERS_IN_LAST_MEMBERS_PAGE < offset)
2552  {
2553  /*
2554  * This is the last page of the last segment; we can compute the
2555  * number of items left to allocate in it without modulo
2556  * arithmetic.
2557  */
2558  difference = MaxMultiXactOffset - offset + 1;
2559  }
2560  else
2562 
2563  /*
2564  * Advance to next page, taking care to properly handle the wraparound
2565  * case. OK if nmembers goes negative.
2566  */
2567  nmembers -= difference;
2568  offset += difference;
2569  }
2570 }
unsigned int uint32
Definition: c.h:493
Datum difference(PG_FUNCTION_ARGS)
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:158
#define MXOffsetToFlagsBitShift(xid)
Definition: multixact.c:166
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE
Definition: multixact.c:154
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:141
#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 2478 of file multixact.c.

2479 {
2480  int64 pageno;
2481  LWLock *lock;
2482 
2483  /*
2484  * No work except at first MultiXactId of a page. But beware: just after
2485  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2486  */
2487  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2488  multi != FirstMultiXactId)
2489  return;
2490 
2491  pageno = MultiXactIdToOffsetPage(multi);
2492  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2493 
2494  LWLockAcquire(lock, LW_EXCLUSIVE);
2495 
2496  /* Zero the page and make an XLOG entry about it */
2497  ZeroMultiXactOffsetPage(pageno, true);
2498 
2499  LWLockRelease(lock);
2500 }
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:112
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:110
#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 2813 of file multixact.c.

2814 {
2815  MultiXactOffset offset;
2816  int64 pageno;
2817  int entryno;
2818  int slotno;
2819  MultiXactOffset *offptr;
2820 
2822 
2823  pageno = MultiXactIdToOffsetPage(multi);
2824  entryno = MultiXactIdToOffsetEntry(multi);
2825 
2826  /*
2827  * Write out dirty data, so PhysicalPageExists can work correctly.
2828  */
2831 
2833  return false;
2834 
2835  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2836  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2837  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2838  offptr += entryno;
2839  offset = *offptr;
2841 
2842  *result = offset;
2843  return true;
2844 }
uint32 MultiXactOffset
Definition: c.h:651
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:591
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int64 pageno)
Definition: slru.c:729

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

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

References Assert(), CHECK_FOR_INTERRUPTS, 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::nextOffset, MultiXactStateData::oldestMultiXactId, OldestVisibleMXactId, palloc(), pg_usleep(), 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 972 of file multixact.c.

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

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

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

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

2044 {
2045  int64 pageno;
2046  LWLock *lock;
2047 
2049  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2050 
2051  LWLockAcquire(lock, LW_EXCLUSIVE);
2052 
2054  {
2055  int slotno;
2056 
2057  /*
2058  * Fortunately for us, SimpleLruWritePage is already prepared to deal
2059  * with creating a new segment file even if the page we're writing is
2060  * not the first in it, so this is enough.
2061  */
2062  slotno = ZeroMultiXactOffsetPage(pageno, false);
2064  }
2065 
2066  LWLockRelease(lock);
2067 }

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

3312 {
3313  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3314 
3315  /* Backup blocks are not used in multixact records */
3316  Assert(!XLogRecHasAnyBlockRefs(record));
3317 
3318  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3319  {
3320  int64 pageno;
3321  int slotno;
3322  LWLock *lock;
3323 
3324  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3325 
3326  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
3327  LWLockAcquire(lock, LW_EXCLUSIVE);
3328 
3329  slotno = ZeroMultiXactOffsetPage(pageno, false);
3331  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3332 
3333  LWLockRelease(lock);
3334  }
3335  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3336  {
3337  int64 pageno;
3338  int slotno;
3339  LWLock *lock;
3340 
3341  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3342 
3343  lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
3344  LWLockAcquire(lock, LW_EXCLUSIVE);
3345 
3346  slotno = ZeroMultiXactMemberPage(pageno, false);
3348  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3349 
3350  LWLockRelease(lock);
3351  }
3352  else if (info == XLOG_MULTIXACT_CREATE_ID)
3353  {
3354  xl_multixact_create *xlrec =
3355  (xl_multixact_create *) XLogRecGetData(record);
3356  TransactionId max_xid;
3357  int i;
3358 
3359  /* Store the data back into the SLRU files */
3360  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3361  xlrec->members);
3362 
3363  /* Make sure nextMXact/nextOffset are beyond what this record has */
3364  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3365  xlrec->moff + xlrec->nmembers);
3366 
3367  /*
3368  * Make sure nextXid is beyond any XID mentioned in the record. This
3369  * should be unnecessary, since any XID found here ought to have other
3370  * evidence in the XLOG, but let's be safe.
3371  */
3372  max_xid = XLogRecGetXid(record);
3373  for (i = 0; i < xlrec->nmembers; i++)
3374  {
3375  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3376  max_xid = xlrec->members[i].xid;
3377  }
3378 
3380  }
3381  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3382  {
3383  xl_multixact_truncate xlrec;
3384  int64 pageno;
3385 
3386  memcpy(&xlrec, XLogRecGetData(record),
3388 
3389  elog(DEBUG1, "replaying multixact truncation: "
3390  "offsets [%u, %u), offsets segments [%x, %x), "
3391  "members [%u, %u), members segments [%x, %x)",
3392  xlrec.startTruncOff, xlrec.endTruncOff,
3395  xlrec.startTruncMemb, xlrec.endTruncMemb,
3398 
3399  /* should not be required, but more than cheap enough */
3400  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3401 
3402  /*
3403  * Advance the horizon values, so they're current at the end of
3404  * recovery.
3405  */
3406  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3407 
3409 
3410  /*
3411  * During XLOG replay, latest_page_number isn't necessarily set up
3412  * yet; insert a suitable value to bypass the sanity test in
3413  * SimpleLruTruncate.
3414  */
3415  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3416  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3417  pageno);
3419 
3420  LWLockRelease(MultiXactTruncationLock);
3421  }
3422  else
3423  elog(PANIC, "multixact_redo: unknown op code %u", info);
3424 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:480
unsigned char uint8
Definition: c.h:491
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2994
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2966
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2287
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:862
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:159
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2436
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:114
#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 1861 of file multixact.c.

1863 {
1864  multixact_twophase_postcommit(xid, info, recdata, len);
1865 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1846
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 1846 of file multixact.c.

1848 {
1849  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, true);
1850 
1851  Assert(len == sizeof(MultiXactId));
1852 
1853  OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1854 }
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 1825 of file multixact.c.

1827 {
1828  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1829  MultiXactId oldestMember;
1830 
1831  /*
1832  * Get the oldest member XID from the state file record, and set it in the
1833  * OldestMemberMXactId slot reserved for this prepared transaction.
1834  */
1835  Assert(len == sizeof(MultiXactId));
1836  oldestMember = *((MultiXactId *) recdata);
1837 
1838  OldestMemberMXactId[dummyProcNumber] = oldestMember;
1839 }

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2436 of file multixact.c.

2438 {
2439  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2441  {
2442  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2443  MultiXactState->nextMXact = minMulti;
2444  }
2445  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2446  {
2447  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2448  minMultiOffset);
2449  MultiXactState->nextOffset = minMultiOffset;
2450  }
2451  LWLockRelease(MultiXactGenLock);
2452 }
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3260

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

2462 {
2463  Assert(InRecovery);
2464 
2466  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2467 }
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 2207 of file multixact.c.

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

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

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

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

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

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

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

3249 {
3250  int32 diff = (int32) (multi1 - multi2);
3251 
3252  return (diff <= 0);
3253 }

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

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

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

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

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

2904 {
2905  MultiXactOffset members;
2906  uint32 multixacts;
2907  uint32 victim_multixacts;
2908  double fraction;
2909 
2910  /* If we can't determine member space utilization, assume the worst. */
2911  if (!ReadMultiXactCounts(&multixacts, &members))
2912  return 0;
2913 
2914  /* If member space utilization is low, no special action is required. */
2915  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2917 
2918  /*
2919  * Compute a target for relminmxid advancement. The number of multixacts
2920  * we try to eliminate from the system is based on how far we are past
2921  * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2922  */
2923  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2925  victim_multixacts = multixacts * fraction;
2926 
2927  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2928  if (victim_multixacts > multixacts)
2929  return 0;
2930  return multixacts - victim_multixacts;
2931 }
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:126
static bool ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
Definition: multixact.c:2851
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:177

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

3215 {
3216  MultiXactOffset offset1;
3217  MultiXactOffset offset2;
3218 
3219  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3220  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3221 
3222  return (MultiXactOffsetPrecedes(offset1, offset2) &&
3223  MultiXactOffsetPrecedes(offset1,
3224  offset2 + MULTIXACT_MEMBERS_PER_PAGE - 1));
3225 }

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3501 of file multixact.c.

3502 {
3503  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3504 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1814

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 3194 of file multixact.c.

3195 {
3196  MultiXactId multi1;
3197  MultiXactId multi2;
3198 
3199  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3200  multi1 += FirstMultiXactId + 1;
3201  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3202  multi2 += FirstMultiXactId + 1;
3203 
3204  return (MultiXactIdPrecedes(multi1, multi2) &&
3205  MultiXactIdPrecedes(multi1,
3206  multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
3207 }
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:108

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

◆ MultiXactOffsetPrecedes()

static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3260 of file multixact.c.

3261 {
3262  int32 diff = (int32) (offset1 - offset2);
3263 
3264  return (diff < 0);
3265 }

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3492 of file multixact.c.

3493 {
3494  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3495 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactOffsetWouldWrap()

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

Definition at line 2765 of file multixact.c.

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

Referenced by GetNewMultiXactId().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2253 of file multixact.c.

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

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

1891 {
1892  bool found;
1893 
1894  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1895 
1898 
1900  "multixact_offset", multixact_offset_buffers, 0,
1901  "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1904  false);
1907  "multixact_member", multixact_member_buffers, 0,
1908  "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1911  false);
1912  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1913 
1914  /* Initialize our shared state struct */
1915  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1917  &found);
1918  if (!IsUnderPostmaster)
1919  {
1920  Assert(!found);
1921 
1922  /* Make sure we zero out the per-backend state */
1924  }
1925  else
1926  Assert(found);
1927 
1928  /*
1929  * Set up array pointers.
1930  */
1933 }
#define MemSet(start, val, len)
Definition: c.h:1007
int multixact_offset_buffers
Definition: globals.c:164
int multixact_member_buffers
Definition: globals.c:163
@ LWTRANCHE_MULTIXACTOFFSET_SLRU
Definition: lwlock.h:214
@ LWTRANCHE_MULTIXACTMEMBER_SLRU
Definition: lwlock.h:213
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:185
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:184
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3214
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3194
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:238
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:203
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:282
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40

References Assert(), 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, 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 1873 of file multixact.c.

1874 {
1875  Size size;
1876 
1877  /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1878 #define SHARED_MULTIXACT_STATE_SIZE \
1879  add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1880  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1881 
1885 
1886  return size;
1887 }
size_t Size
Definition: c.h:592
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 1588 of file multixact.c.

1589 {
1590  dlist_iter iter;
1591 
1592  debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1593 
1594  dclist_foreach(iter, &MXactCache)
1595  {
1597  iter.cur);
1598 
1599  if (entry->multi == multi)
1600  {
1601  MultiXactMember *ptr;
1602  Size size;
1603 
1604  size = sizeof(MultiXactMember) * entry->nmembers;
1605  ptr = (MultiXactMember *) palloc(size);
1606 
1607  memcpy(ptr, entry->members, size);
1608 
1609  debug_elog3(DEBUG2, "CacheGet: found %s",
1610  mxid_to_string(multi,
1611  entry->nmembers,
1612  entry->members));
1613 
1614  /*
1615  * Note we modify the list while not using a modifiable iterator.
1616  * This is acceptable only because we exit the iteration
1617  * immediately afterwards.
1618  */
1620 
1621  *members = ptr;
1622  return entry->nmembers;
1623  }
1624  }
1625 
1626  debug_elog2(DEBUG2, "CacheGet: not found");
1627  return -1;
1628 }
#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:315
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:318

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

1546 {
1547  dlist_iter iter;
1548 
1549  debug_elog3(DEBUG2, "CacheGet: looking for %s",
1550  mxid_to_string(InvalidMultiXactId, nmembers, members));
1551 
1552  /* sort the array so comparison is easy */
1553  qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1554 
1555  dclist_foreach(iter, &MXactCache)
1556  {
1558  iter.cur);
1559 
1560  if (entry->nmembers != nmembers)
1561  continue;
1562 
1563  /*
1564  * We assume the cache entries are sorted, and that the unused bits in
1565  * "status" are zeroed.
1566  */
1567  if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1568  {
1569  debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1571  return entry->multi;
1572  }
1573  }
1574 
1575  debug_elog2(DEBUG2, "CacheGet: not found :-(");
1576  return InvalidMultiXactId;
1577 }
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition: multixact.c:1515
#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 1635 of file multixact.c.

1636 {
1637  mXactCacheEnt *entry;
1638 
1639  debug_elog3(DEBUG2, "CachePut: storing %s",
1640  mxid_to_string(multi, nmembers, members));
1641 
1642  if (MXactContext == NULL)
1643  {
1644  /* The cache only lives as long as the current transaction */
1645  debug_elog2(DEBUG2, "CachePut: initializing memory context");
1647  "MultiXact cache context",
1649  }
1650 
1651  entry = (mXactCacheEnt *)
1653  offsetof(mXactCacheEnt, members) +
1654  nmembers * sizeof(MultiXactMember));
1655 
1656  entry->multi = multi;
1657  entry->nmembers = nmembers;
1658  memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1659 
1660  /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1661  qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1662 
1663  dclist_push_head(&MXactCache, &entry->node);
1665  {
1666  dlist_node *node;
1667 
1668  node = dclist_tail_node(&MXactCache);
1670 
1671  entry = dclist_container(mXactCacheEnt, node, node);
1672  debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1673  entry->multi);
1674 
1675  pfree(entry);
1676  }
1677 }
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:142
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1168
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
#define MAX_CACHE_ENTRIES
Definition: multixact.c:321
dlist_node node
Definition: multixact.c:317

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

1516 {
1517  MultiXactMember member1 = *(const MultiXactMember *) arg1;
1518  MultiXactMember member2 = *(const MultiXactMember *) arg2;
1519 
1520  if (member1.xid > member2.xid)
1521  return 1;
1522  if (member1.xid < member2.xid)
1523  return -1;
1524  if (member1.status > member2.status)
1525  return 1;
1526  if (member1.status < member2.status)
1527  return -1;
1528  return 0;
1529 }

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

1704 {
1705  static char *str = NULL;
1707  int i;
1708 
1709  if (str != NULL)
1710  pfree(str);
1711 
1712  initStringInfo(&buf);
1713 
1714  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1715  mxstatus_to_string(members[0].status));
1716 
1717  for (i = 1; i < nmembers; i++)
1718  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1719  mxstatus_to_string(members[i].status));
1720 
1721  appendStringInfoChar(&buf, ']');
1723  pfree(buf.data);
1724  return str;
1725 }
MemoryContext TopMemoryContext
Definition: mcxt.c:137
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1670
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(), generate_unaccent_rules::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 1680 of file multixact.c.

1681 {
1682  switch (status)
1683  {
1685  return "keysh";
1687  return "sh";
1689  return "fornokeyupd";
1691  return "forupd";
1693  return "nokeyupd";
1694  case MultiXactStatusUpdate:
1695  return "upd";
1696  default:
1697  elog(ERROR, "unrecognized multixact status %d", status);
1698  return "";
1699  }
1700 }
@ 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 2966 of file multixact.c.

2967 {
2968  const int maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
2969  int startsegment = MXOffsetToMemberSegment(oldestOffset);
2970  int endsegment = MXOffsetToMemberSegment(newOldestOffset);
2971  int segment = startsegment;
2972 
2973  /*
2974  * Delete all the segments but the last one. The last segment can still
2975  * contain, possibly partially, valid data.
2976  */
2977  while (segment != endsegment)
2978  {
2979  elog(DEBUG2, "truncating multixact members segment %x", segment);
2981 
2982  /* move to next segment, handling wraparound correctly */
2983  if (segment == maxsegment)
2984  segment = 0;
2985  else
2986  segment += 1;
2987  }
2988 }
void SlruDeleteSegment(SlruCtl ctl, int64 segno)
Definition: slru.c:1509

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

2995 {
2996  /*
2997  * We step back one multixact to avoid passing a cutoff page that hasn't
2998  * been created yet in the rare case that oldestMulti would be the first
2999  * item on a page and oldestMulti == nextMulti. In that case, if we
3000  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
3001  * detection.
3002  */
3004  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
3005 }
#define PreviousMultiXactId(xid)
Definition: multixact.c:180
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition: slru.c:1391

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

3428 {
3429  typedef struct
3430  {
3431  MultiXactMember *members;
3432  int nmembers;
3433  int iter;
3434  } mxact;
3436  mxact *multi;
3437  FuncCallContext *funccxt;
3438 
3439  if (mxid < FirstMultiXactId)
3440  ereport(ERROR,
3441  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3442  errmsg("invalid MultiXactId: %u", mxid)));
3443 
3444  if (SRF_IS_FIRSTCALL())
3445  {
3446  MemoryContext oldcxt;
3447  TupleDesc tupdesc;
3448 
3449  funccxt = SRF_FIRSTCALL_INIT();
3450  oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3451 
3452  multi = palloc(sizeof(mxact));
3453  /* no need to allow for old values here */
3454  multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3455  false);
3456  multi->iter = 0;
3457 
3458  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3459  elog(ERROR, "return type must be a row type");
3460  funccxt->tuple_desc = tupdesc;
3461  funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3462  funccxt->user_fctx = multi;
3463 
3464  MemoryContextSwitchTo(oldcxt);
3465  }
3466 
3467  funccxt = SRF_PERCALL_SETUP();
3468  multi = (mxact *) funccxt->user_fctx;
3469 
3470  while (multi->iter < multi->nmembers)
3471  {
3472  HeapTuple tuple;
3473  char *values[2];
3474 
3475  values[0] = psprintf("%u", multi->members[multi->iter].xid);
3476  values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3477 
3478  tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3479 
3480  multi->iter++;
3481  pfree(values[0]);
3482  SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3483  }
3484 
3485  SRF_RETURN_DONE(funccxt);
3486 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2134
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2085
#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
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
while(p+4<=pend)
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
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 1776 of file multixact.c.

1777 {
1778  MultiXactId myOldestMember;
1779 
1780  /*
1781  * Transfer our OldestMemberMXactId value to the slot reserved for the
1782  * prepared transaction.
1783  */
1784  myOldestMember = OldestMemberMXactId[MyProcNumber];
1785  if (MultiXactIdIsValid(myOldestMember))
1786  {
1787  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1788 
1789  /*
1790  * Even though storing MultiXactId is atomic, acquire lock to make
1791  * sure others see both changes, not just the reset of the slot of the
1792  * current backend. Using a volatile pointer might suffice, but this
1793  * isn't a hot spot.
1794  */
1795  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1796 
1797  OldestMemberMXactId[dummyProcNumber] = myOldestMember;
1799 
1800  LWLockRelease(MultiXactGenLock);
1801  }
1802 
1803  /*
1804  * We don't need to transfer OldestVisibleMXactId value, because the
1805  * transaction is not going to be looking at any more multixacts once it's
1806  * prepared.
1807  *
1808  * We assume that storing a MultiXactId is atomic and so we need not take
1809  * MultiXactGenLock to do this.
1810  */
1812 
1813  /*
1814  * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1815  */
1816  MXactContext = NULL;
1818 }

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

2852 {
2853  MultiXactOffset nextOffset;
2854  MultiXactOffset oldestOffset;
2855  MultiXactId oldestMultiXactId;
2856  MultiXactId nextMultiXactId;
2857  bool oldestOffsetKnown;
2858 
2859  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2860  nextOffset = MultiXactState->nextOffset;
2861  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2862  nextMultiXactId = MultiXactState->nextMXact;
2863  oldestOffset = MultiXactState->oldestOffset;
2864  oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2865  LWLockRelease(MultiXactGenLock);
2866 
2867  if (!oldestOffsetKnown)
2868  return false;
2869 
2870  *members = nextOffset - oldestOffset;
2871  *multixacts = nextMultiXactId - oldestMultiXactId;
2872  return true;
2873 }

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

743 {
744  LWLockAcquire(MultiXactGenLock, LW_SHARED);
747  LWLockRelease(MultiXactGenLock);
748 
749  if (*oldest < FirstMultiXactId)
750  *oldest = FirstMultiXactId;
751  if (*next < FirstMultiXactId)
753 }
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 722 of file multixact.c.

723 {
724  MultiXactId mxid;
725 
726  /* XXX we could presumably do this without a lock. */
727  LWLockAcquire(MultiXactGenLock, LW_SHARED);
728  mxid = MultiXactState->nextMXact;
729  LWLockRelease(MultiXactGenLock);
730 
731  if (mxid < FirstMultiXactId)
732  mxid = FirstMultiXactId;
733 
734  return mxid;
735 }

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

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

References Assert(), i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactStatusUpdate, MXACT_MEMBER_BITS_PER_XACT, MXOffsetToFlagsBitShift, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, 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 2287 of file multixact.c.

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

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

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

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

2944 {
2945  mxtruncinfo *trunc = (mxtruncinfo *) data;
2946 
2947  if (trunc->earliestExistingPage == -1 ||
2948  ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
2949  {
2950  trunc->earliestExistingPage = segpage;
2951  }
2952 
2953  return false; /* keep going */
2954 }
const void * data
bool(* PagePrecedes)(int64, int64)
Definition: slru.h:160
int64 earliestExistingPage
Definition: multixact.c:2935

References data, mxtruncinfo::earliestExistingPage, and SlruCtlData::PagePrecedes.

Referenced by TruncateMultiXact().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2078 of file multixact.c.

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

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

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

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

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

3289 {
3290  XLogRecPtr recptr;
3291  xl_multixact_truncate xlrec;
3292 
3293  xlrec.oldestMultiDB = oldestMultiDB;
3294 
3295  xlrec.startTruncOff = startTruncOff;
3296  xlrec.endTruncOff = endTruncOff;
3297 
3298  xlrec.startTruncMemb = startTruncMemb;
3299  xlrec.endTruncMemb = endTruncMemb;
3300 
3301  XLogBeginInsert();
3302  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3303  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3304  XLogFlush(recptr);
3305 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2728
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 3272 of file multixact.c.

3273 {
3274  XLogBeginInsert();
3275  XLogRegisterData((char *) (&pageno), sizeof(pageno));
3276  (void) XLogInsert(RM_MULTIXACT_ID, info);
3277 }

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

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

◆ ZeroMultiXactMemberPage()

static int ZeroMultiXactMemberPage ( int64  pageno,
bool  writeXlog 
)
static

Definition at line 2015 of file multixact.c.

2016 {
2017  int slotno;
2018 
2019  slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
2020 
2021  if (writeXlog)
2023 
2024  return slotno;
2025 }
static void WriteMZeroPageXlogRec(int64 pageno, uint8 info)
Definition: multixact.c:3272
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:361

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

2000 {
2001  int slotno;
2002 
2003  slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
2004 
2005  if (writeXlog)
2007 
2008  return slotno;
2009 }

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

◆ MultiXactOffsetCtlData

SlruCtlData MultiXactOffsetCtlData
static

Definition at line 186 of file multixact.c.

◆ MultiXactState

◆ MXactCache

◆ MXactContext

MemoryContext MXactContext = NULL
static

Definition at line 323 of file multixact.c.

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

◆ OldestMemberMXactId

◆ OldestVisibleMXactId