PostgreSQL Source Code  git master
multixact.c File Reference
#include "postgres.h"
#include "access/multixact.h"
#include "access/slru.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "commands/dbcommands.h"
#include "funcapi.h"
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/fmgrprotos.h"
#include "utils/guc_hooks.h"
#include "utils/memutils.h"
Include dependency graph for multixact.c:

Go to the source code of this file.

Data Structures

struct  MultiXactStateData
 
struct  mXactCacheEnt
 
struct  mxtruncinfo
 

Macros

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

Typedefs

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

Functions

static int64 MultiXactIdToOffsetPage (MultiXactId multi)
 
static int MultiXactIdToOffsetEntry (MultiXactId multi)
 
static int MultiXactIdToOffsetSegment (MultiXactId multi)
 
static int64 MXOffsetToMemberPage (MultiXactOffset offset)
 
static int MXOffsetToMemberSegment (MultiXactOffset offset)
 
static int MXOffsetToFlagsOffset (MultiXactOffset offset)
 
static int MXOffsetToFlagsBitShift (MultiXactOffset offset)
 
static int MXOffsetToMemberOffset (MultiXactOffset offset)
 
static MultiXactId PreviousMultiXactId (MultiXactId multi)
 
static void MultiXactIdSetOldestVisible (void)
 
static void RecordNewMultiXact (MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
 
static MultiXactId GetNewMultiXactId (int nmembers, MultiXactOffset *offset)
 
static int mxactMemberComparator (const void *arg1, const void *arg2)
 
static MultiXactId mXactCacheGetBySet (int nmembers, MultiXactMember *members)
 
static int mXactCacheGetById (MultiXactId multi, MultiXactMember **members)
 
static void mXactCachePut (MultiXactId multi, int nmembers, MultiXactMember *members)
 
static 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 380 of file multixact.c.

◆ debug_elog3

#define debug_elog3 (   a,
  b,
  c 
)

Definition at line 381 of file multixact.c.

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

Definition at line 382 of file multixact.c.

◆ debug_elog5

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

Definition at line 383 of file multixact.c.

◆ debug_elog6

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

Definition at line 384 of file multixact.c.

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

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

◆ MaxOldestSlot

#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)

Definition at line 336 of file multixact.c.

◆ MULTIXACT_FLAGBYTES_PER_GROUP

#define MULTIXACT_FLAGBYTES_PER_GROUP   4

Definition at line 147 of file multixact.c.

◆ MULTIXACT_MEMBER_DANGER_THRESHOLD

#define MULTIXACT_MEMBER_DANGER_THRESHOLD    (MaxMultiXactOffset - MaxMultiXactOffset / 4)

Definition at line 216 of file multixact.c.

◆ MULTIXACT_MEMBER_SAFE_THRESHOLD

#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)

Definition at line 215 of file multixact.c.

◆ MULTIXACT_MEMBERGROUP_SIZE

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

Definition at line 151 of file multixact.c.

◆ MULTIXACT_MEMBERGROUPS_PER_PAGE

#define MULTIXACT_MEMBERGROUPS_PER_PAGE   (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)

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

◆ MULTIXACT_MEMBERS_PER_PAGE

#define MULTIXACT_MEMBERS_PER_PAGE    (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)

Definition at line 154 of file multixact.c.

◆ MULTIXACT_OFFSETS_PER_PAGE

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))

Definition at line 109 of file multixact.c.

◆ MultiXactMemberCtl

#define MultiXactMemberCtl   (&MultiXactMemberCtlData)

Definition at line 232 of file multixact.c.

◆ MultiXactOffsetCtl

#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)

Definition at line 231 of file multixact.c.

◆ MXACT_MEMBER_BITS_PER_XACT

#define MXACT_MEMBER_BITS_PER_XACT   8

Definition at line 142 of file multixact.c.

◆ MXACT_MEMBER_FLAGS_PER_BYTE

#define MXACT_MEMBER_FLAGS_PER_BYTE   1

Definition at line 143 of file multixact.c.

◆ MXACT_MEMBER_XACT_BITMASK

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

Definition at line 144 of file multixact.c.

◆ OFFSET_WARN_SEGMENTS

#define OFFSET_WARN_SEGMENTS   20

◆ SHARED_MULTIXACT_STATE_SIZE

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

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

1829 {
1830  MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
1831 
1832  if (MultiXactIdIsValid(myOldestMember))
1834  &myOldestMember, sizeof(MultiXactId));
1835 }
#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 2026 of file multixact.c.

2027 {
2028  int slotno;
2029  LWLock *lock;
2030 
2032  LWLockAcquire(lock, LW_EXCLUSIVE);
2033 
2034  /* Create and zero the first page of the offsets log */
2035  slotno = ZeroMultiXactOffsetPage(0, false);
2036 
2037  /* Make sure it's written out */
2039  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
2040 
2041  LWLockRelease(lock);
2042 
2044  LWLockAcquire(lock, LW_EXCLUSIVE);
2045 
2046  /* Create and zero the first page of the members log */
2047  slotno = ZeroMultiXactMemberPage(0, false);
2048 
2049  /* Make sure it's written out */
2051  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
2052 
2053  LWLockRelease(lock);
2054 }
#define Assert(condition)
Definition: c.h:858
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_EXCLUSIVE
Definition: lwlock.h:114
static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2082
#define MultiXactMemberCtl
Definition: multixact.c:232
#define MultiXactOffsetCtl
Definition: multixact.c:231
static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2066
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:729
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:178
Definition: lwlock.h:42

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

Referenced by BootStrapXLOG().

◆ check_multixact_member_buffers()

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

Definition at line 2015 of file multixact.c.

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

References check_slru_buffers(), and newval.

◆ check_multixact_offset_buffers()

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

Definition at line 2006 of file multixact.c.

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

References check_slru_buffers(), and newval.

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2296 of file multixact.c.

2297 {
2298  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2299 
2300  /*
2301  * Write dirty MultiXact pages to disk. This may result in sync requests
2302  * queued for later handling by ProcessSyncRequests(), as part of the
2303  * checkpoint.
2304  */
2307 
2308  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2309 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1319

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ ExtendMultiXactMember()

static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2577 of file multixact.c.

2578 {
2579  /*
2580  * It's possible that the members span more than one page of the members
2581  * file, so we loop to ensure we consider each page. The coding is not
2582  * optimal if the members span several pages, but that seems unusual
2583  * enough to not worry much about.
2584  */
2585  while (nmembers > 0)
2586  {
2587  int flagsoff;
2588  int flagsbit;
2590 
2591  /*
2592  * Only zero when at first entry of a page.
2593  */
2594  flagsoff = MXOffsetToFlagsOffset(offset);
2595  flagsbit = MXOffsetToFlagsBitShift(offset);
2596  if (flagsoff == 0 && flagsbit == 0)
2597  {
2598  int64 pageno;
2599  LWLock *lock;
2600 
2601  pageno = MXOffsetToMemberPage(offset);
2602  lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
2603 
2604  LWLockAcquire(lock, LW_EXCLUSIVE);
2605 
2606  /* Zero the page and make an XLOG entry about it */
2607  ZeroMultiXactMemberPage(pageno, true);
2608 
2609  LWLockRelease(lock);
2610  }
2611 
2612  /*
2613  * Compute the number of items till end of current page. Careful: if
2614  * addition of unsigned ints wraps around, we're at the last page of
2615  * the last segment; since that page holds a different number of items
2616  * than other pages, we need to do it differently.
2617  */
2618  if (offset + MAX_MEMBERS_IN_LAST_MEMBERS_PAGE < offset)
2619  {
2620  /*
2621  * This is the last page of the last segment; we can compute the
2622  * number of items left to allocate in it without modulo
2623  * arithmetic.
2624  */
2625  difference = MaxMultiXactOffset - offset + 1;
2626  }
2627  else
2629 
2630  /*
2631  * Advance to next page, taking care to properly handle the wraparound
2632  * case. OK if nmembers goes negative.
2633  */
2634  nmembers -= difference;
2635  offset += difference;
2636  }
2637 }
unsigned int uint32
Definition: c.h:506
Datum difference(PG_FUNCTION_ARGS)
static int64 MXOffsetToMemberPage(MultiXactOffset offset)
Definition: multixact.c:172
static int MXOffsetToFlagsOffset(MultiXactOffset offset)
Definition: multixact.c:185
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE
Definition: multixact.c:167
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:154
static int MXOffsetToFlagsBitShift(MultiXactOffset offset)
Definition: multixact.c:195
#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 2545 of file multixact.c.

2546 {
2547  int64 pageno;
2548  LWLock *lock;
2549 
2550  /*
2551  * No work except at first MultiXactId of a page. But beware: just after
2552  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2553  */
2554  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2555  multi != FirstMultiXactId)
2556  return;
2557 
2558  pageno = MultiXactIdToOffsetPage(multi);
2559  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2560 
2561  LWLockAcquire(lock, LW_EXCLUSIVE);
2562 
2563  /* Zero the page and make an XLOG entry about it */
2564  ZeroMultiXactOffsetPage(pageno, true);
2565 
2566  LWLockRelease(lock);
2567 }
static int MultiXactIdToOffsetEntry(MultiXactId multi)
Definition: multixact.c:118
static int64 MultiXactIdToOffsetPage(MultiXactId multi)
Definition: multixact.c:112
#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 2880 of file multixact.c.

2881 {
2882  MultiXactOffset offset;
2883  int64 pageno;
2884  int entryno;
2885  int slotno;
2886  MultiXactOffset *offptr;
2887 
2889 
2890  pageno = MultiXactIdToOffsetPage(multi);
2891  entryno = MultiXactIdToOffsetEntry(multi);
2892 
2893  /*
2894  * Write out dirty data, so PhysicalPageExists can work correctly.
2895  */
2898 
2900  return false;
2901 
2902  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2903  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2904  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2905  offptr += entryno;
2906  offset = *offptr;
2908 
2909  *result = offset;
2910  return true;
2911 }
uint32 MultiXactOffset
Definition: c.h:664
static MultiXactStateData * MultiXactState
Definition: multixact.c:339
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:605
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int64 pageno)
Definition: slru.c:743

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

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

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

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

◆ GetNewMultiXactId()

static MultiXactId GetNewMultiXactId ( int  nmembers,
MultiXactOffset offset 
)
static

Definition at line 1026 of file multixact.c.

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

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

Referenced by MultiXactIdCreateFromMembers().

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2652 of file multixact.c.

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

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

2111 {
2112  int64 pageno;
2113  LWLock *lock;
2114 
2116  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2117 
2118  LWLockAcquire(lock, LW_EXCLUSIVE);
2119 
2121  {
2122  int slotno;
2123 
2124  /*
2125  * Fortunately for us, SimpleLruWritePage is already prepared to deal
2126  * with creating a new segment file even if the page we're writing is
2127  * not the first in it, so this is enough.
2128  */
2129  slotno = ZeroMultiXactOffsetPage(pageno, false);
2131  }
2132 
2133  LWLockRelease(lock);
2134 }

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

3386 {
3387  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3388 
3389  /* Backup blocks are not used in multixact records */
3390  Assert(!XLogRecHasAnyBlockRefs(record));
3391 
3392  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3393  {
3394  int64 pageno;
3395  int slotno;
3396  LWLock *lock;
3397 
3398  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3399 
3400  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
3401  LWLockAcquire(lock, LW_EXCLUSIVE);
3402 
3403  slotno = ZeroMultiXactOffsetPage(pageno, false);
3405  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3406 
3407  LWLockRelease(lock);
3408  }
3409  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3410  {
3411  int64 pageno;
3412  int slotno;
3413  LWLock *lock;
3414 
3415  memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
3416 
3417  lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
3418  LWLockAcquire(lock, LW_EXCLUSIVE);
3419 
3420  slotno = ZeroMultiXactMemberPage(pageno, false);
3422  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3423 
3424  LWLockRelease(lock);
3425  }
3426  else if (info == XLOG_MULTIXACT_CREATE_ID)
3427  {
3428  xl_multixact_create *xlrec =
3429  (xl_multixact_create *) XLogRecGetData(record);
3430  TransactionId max_xid;
3431  int i;
3432 
3433  /* Store the data back into the SLRU files */
3434  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3435  xlrec->members);
3436 
3437  /* Make sure nextMXact/nextOffset are beyond what this record has */
3438  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3439  xlrec->moff + xlrec->nmembers);
3440 
3441  /*
3442  * Make sure nextXid is beyond any XID mentioned in the record. This
3443  * should be unnecessary, since any XID found here ought to have other
3444  * evidence in the XLOG, but let's be safe.
3445  */
3446  max_xid = XLogRecGetXid(record);
3447  for (i = 0; i < xlrec->nmembers; i++)
3448  {
3449  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3450  max_xid = xlrec->members[i].xid;
3451  }
3452 
3454  }
3455  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3456  {
3457  xl_multixact_truncate xlrec;
3458  int64 pageno;
3459 
3460  memcpy(&xlrec, XLogRecGetData(record),
3462 
3463  elog(DEBUG1, "replaying multixact truncation: "
3464  "offsets [%u, %u), offsets segments [%x, %x), "
3465  "members [%u, %u), members segments [%x, %x)",
3466  xlrec.startTruncOff, xlrec.endTruncOff,
3469  xlrec.startTruncMemb, xlrec.endTruncMemb,
3472 
3473  /* should not be required, but more than cheap enough */
3474  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3475 
3476  /*
3477  * Advance the horizon values, so they're current at the end of
3478  * recovery.
3479  */
3480  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3481 
3483 
3484  /*
3485  * During XLOG replay, latest_page_number isn't necessarily set up
3486  * yet; insert a suitable value to bypass the sanity test in
3487  * SimpleLruTruncate.
3488  */
3489  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3490  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
3491  pageno);
3493 
3494  LWLockRelease(MultiXactTruncationLock);
3495  }
3496  else
3497  elog(PANIC, "multixact_redo: unknown op code %u", info);
3498 }
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:478
unsigned char uint8
Definition: c.h:504
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:3068
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:3040
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2354
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:910
static int MXOffsetToMemberSegment(MultiXactOffset offset)
Definition: multixact.c:178
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2503
static int MultiXactIdToOffsetSegment(MultiXactId multi)
Definition: multixact.c:124
#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 1927 of file multixact.c.

1929 {
1930  multixact_twophase_postcommit(xid, info, recdata, len);
1931 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1912
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 1912 of file multixact.c.

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

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

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2503 of file multixact.c.

2505 {
2506  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2508  {
2509  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2510  MultiXactState->nextMXact = minMulti;
2511  }
2512  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2513  {
2514  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2515  minMultiOffset);
2516  MultiXactState->nextOffset = minMultiOffset;
2517  }
2518  LWLockRelease(MultiXactGenLock);
2519 }
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3334

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

2529 {
2530  Assert(InRecovery);
2531 
2533  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2534 }
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 2274 of file multixact.c.

2279 {
2280  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2281  *nextMulti = MultiXactState->nextMXact;
2282  *nextMultiOffset = MultiXactState->nextOffset;
2283  *oldestMulti = MultiXactState->oldestMultiXactId;
2284  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2285  LWLockRelease(MultiXactGenLock);
2286 
2288  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2289  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2290 }
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:384

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

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

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

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

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

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdIsRunning()

bool MultiXactIdIsRunning ( MultiXactId  multi,
bool  isLockOnly 
)

Definition at line 598 of file multixact.c.

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

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

3323 {
3324  int32 diff = (int32) (multi1 - multi2);
3325 
3326  return (diff <= 0);
3327 }

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

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

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

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

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

Referenced by GetMultiXactIdMembers().

◆ MultiXactIdToOffsetEntry()

static int MultiXactIdToOffsetEntry ( MultiXactId  multi)
inlinestatic

Definition at line 118 of file multixact.c.

119 {
120  return multi % MULTIXACT_OFFSETS_PER_PAGE;
121 }
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109

References MULTIXACT_OFFSETS_PER_PAGE.

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

◆ MultiXactIdToOffsetPage()

◆ MultiXactIdToOffsetSegment()

static int MultiXactIdToOffsetSegment ( MultiXactId  multi)
inlinestatic

Definition at line 124 of file multixact.c.

125 {
127 }

References MultiXactIdToOffsetPage(), and SLRU_PAGES_PER_SEGMENT.

Referenced by multixact_redo(), and TruncateMultiXact().

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2970 of file multixact.c.

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

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

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

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 3288 of file multixact.c.

3289 {
3290  MultiXactOffset offset1;
3291  MultiXactOffset offset2;
3292 
3293  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3294  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3295 
3296  return (MultiXactOffsetPrecedes(offset1, offset2) &&
3297  MultiXactOffsetPrecedes(offset1,
3298  offset2 + MULTIXACT_MEMBERS_PER_PAGE - 1));
3299 }

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3575 of file multixact.c.

3576 {
3577  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3578 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1828

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 3268 of file multixact.c.

3269 {
3270  MultiXactId multi1;
3271  MultiXactId multi2;
3272 
3273  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3274  multi1 += FirstMultiXactId + 1;
3275  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3276  multi2 += FirstMultiXactId + 1;
3277 
3278  return (MultiXactIdPrecedes(multi1, multi2) &&
3279  MultiXactIdPrecedes(multi1,
3280  multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
3281 }

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

◆ MultiXactOffsetPrecedes()

static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3334 of file multixact.c.

3335 {
3336  int32 diff = (int32) (offset1 - offset2);
3337 
3338  return (diff < 0);
3339 }

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3566 of file multixact.c.

3567 {
3568  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3569 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactOffsetWouldWrap()

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

Definition at line 2832 of file multixact.c.

2834 {
2835  MultiXactOffset finish;
2836 
2837  /*
2838  * Note that offset number 0 is not used (see GetMultiXactIdMembers), so
2839  * if the addition wraps around the UINT_MAX boundary, skip that value.
2840  */
2841  finish = start + distance;
2842  if (finish < start)
2843  finish++;
2844 
2845  /*-----------------------------------------------------------------------
2846  * When the boundary is numerically greater than the starting point, any
2847  * value numerically between the two is not wrapped:
2848  *
2849  * <----S----B---->
2850  * [---) = F wrapped past B (and UINT_MAX)
2851  * [---) = F not wrapped
2852  * [----] = F wrapped past B
2853  *
2854  * When the boundary is numerically less than the starting point (i.e. the
2855  * UINT_MAX wraparound occurs somewhere in between) then all values in
2856  * between are wrapped:
2857  *
2858  * <----B----S---->
2859  * [---) = F not wrapped past B (but wrapped past UINT_MAX)
2860  * [---) = F wrapped past B (and UINT_MAX)
2861  * [----] = F not wrapped
2862  *-----------------------------------------------------------------------
2863  */
2864  if (start < boundary)
2865  return finish >= boundary || finish < start;
2866  else
2867  return finish >= boundary && finish < start;
2868 }
return str start

References start.

Referenced by GetNewMultiXactId().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2320 of file multixact.c.

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

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

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

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

Referenced by CreateOrAttachShmemStructs().

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1939 of file multixact.c.

1940 {
1941  Size size;
1942 
1943  /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1944 #define SHARED_MULTIXACT_STATE_SIZE \
1945  add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1946  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1947 
1951 
1952  return size;
1953 }
size_t Size
Definition: c.h:605
static pg_noinline void Size size
Definition: slab.c:607
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:199

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

1655 {
1656  dlist_iter iter;
1657 
1658  debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1659 
1660  dclist_foreach(iter, &MXactCache)
1661  {
1663  iter.cur);
1664 
1665  if (entry->multi == multi)
1666  {
1667  MultiXactMember *ptr;
1668  Size size;
1669 
1670  size = sizeof(MultiXactMember) * entry->nmembers;
1671  ptr = (MultiXactMember *) palloc(size);
1672 
1673  memcpy(ptr, entry->members, size);
1674 
1675  debug_elog3(DEBUG2, "CacheGet: found %s",
1676  mxid_to_string(multi,
1677  entry->nmembers,
1678  entry->members));
1679 
1680  /*
1681  * Note we modify the list while not using a modifiable iterator.
1682  * This is acceptable only because we exit the iteration
1683  * immediately afterwards.
1684  */
1686 
1687  *members = ptr;
1688  return entry->nmembers;
1689  }
1690  }
1691 
1692  debug_elog2(DEBUG2, "CacheGet: not found");
1693  return -1;
1694 }
#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:363
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:366

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

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

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

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

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

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

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

1770 {
1771  static char *str = NULL;
1773  int i;
1774 
1775  if (str != NULL)
1776  pfree(str);
1777 
1778  initStringInfo(&buf);
1779 
1780  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1781  mxstatus_to_string(members[0].status));
1782 
1783  for (i = 1; i < nmembers; i++)
1784  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1785  mxstatus_to_string(members[i].status));
1786 
1787  appendStringInfoChar(&buf, ']');
1789  pfree(buf.data);
1790  return str;
1791 }
const char * str
MemoryContext TopMemoryContext
Definition: mcxt.c:149
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1683
static char * buf
Definition: pg_test_fsync.c:73
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

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

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

◆ MXOffsetToFlagsBitShift()

static int MXOffsetToFlagsBitShift ( MultiXactOffset  offset)
inlinestatic

Definition at line 195 of file multixact.c.

196 {
197  int member_in_group = offset % MULTIXACT_MEMBERS_PER_MEMBERGROUP;
198  int bshift = member_in_group * MXACT_MEMBER_BITS_PER_XACT;
199 
200  return bshift;
201 }
#define MXACT_MEMBER_BITS_PER_XACT
Definition: multixact.c:142
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP
Definition: multixact.c:148

References MULTIXACT_MEMBERS_PER_MEMBERGROUP, and MXACT_MEMBER_BITS_PER_XACT.

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

◆ MXOffsetToFlagsOffset()

static int MXOffsetToFlagsOffset ( MultiXactOffset  offset)
inlinestatic

Definition at line 185 of file multixact.c.

186 {
188  int grouponpg = group % MULTIXACT_MEMBERGROUPS_PER_PAGE;
189  int byteoff = grouponpg * MULTIXACT_MEMBERGROUP_SIZE;
190 
191  return byteoff;
192 }
#define MULTIXACT_MEMBERGROUPS_PER_PAGE
Definition: multixact.c:153
#define MULTIXACT_MEMBERGROUP_SIZE
Definition: multixact.c:151

References MULTIXACT_MEMBERGROUP_SIZE, MULTIXACT_MEMBERGROUPS_PER_PAGE, and MULTIXACT_MEMBERS_PER_MEMBERGROUP.

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

◆ MXOffsetToMemberOffset()

static int MXOffsetToMemberOffset ( MultiXactOffset  offset)
inlinestatic

Definition at line 205 of file multixact.c.

206 {
207  int member_in_group = offset % MULTIXACT_MEMBERS_PER_MEMBERGROUP;
208 
209  return MXOffsetToFlagsOffset(offset) +
211  member_in_group * sizeof(TransactionId);
212 }
#define MULTIXACT_FLAGBYTES_PER_GROUP
Definition: multixact.c:147

References MULTIXACT_FLAGBYTES_PER_GROUP, MULTIXACT_MEMBERS_PER_MEMBERGROUP, and MXOffsetToFlagsOffset().

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

◆ MXOffsetToMemberPage()

static int64 MXOffsetToMemberPage ( MultiXactOffset  offset)
inlinestatic

◆ MXOffsetToMemberSegment()

static int MXOffsetToMemberSegment ( MultiXactOffset  offset)
inlinestatic

Definition at line 178 of file multixact.c.

179 {
181 }

References MXOffsetToMemberPage(), and SLRU_PAGES_PER_SEGMENT.

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

◆ mxstatus_to_string()

static char * mxstatus_to_string ( MultiXactStatus  status)
static

Definition at line 1746 of file multixact.c.

1747 {
1748  switch (status)
1749  {
1751  return "keysh";
1753  return "sh";
1755  return "fornokeyupd";
1757  return "forupd";
1759  return "nokeyupd";
1760  case MultiXactStatusUpdate:
1761  return "upd";
1762  default:
1763  elog(ERROR, "unrecognized multixact status %d", status);
1764  return "";
1765  }
1766 }
@ 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 3040 of file multixact.c.

3041 {
3042  const int maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
3043  int startsegment = MXOffsetToMemberSegment(oldestOffset);
3044  int endsegment = MXOffsetToMemberSegment(newOldestOffset);
3045  int segment = startsegment;
3046 
3047  /*
3048  * Delete all the segments but the last one. The last segment can still
3049  * contain, possibly partially, valid data.
3050  */
3051  while (segment != endsegment)
3052  {
3053  elog(DEBUG2, "truncating multixact members segment %x", segment);
3055 
3056  /* move to next segment, handling wraparound correctly */
3057  if (segment == maxsegment)
3058  segment = 0;
3059  else
3060  segment += 1;
3061  }
3062 }
void SlruDeleteSegment(SlruCtl ctl, int64 segno)
Definition: slru.c:1523

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

3069 {
3070  /*
3071  * We step back one multixact to avoid passing a cutoff page that hasn't
3072  * been created yet in the rare case that oldestMulti would be the first
3073  * item on a page and oldestMulti == nextMulti. In that case, if we
3074  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
3075  * detection.
3076  */
3078  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
3079 }
static MultiXactId PreviousMultiXactId(MultiXactId multi)
Definition: multixact.c:220
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition: slru.c:1405

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

3502 {
3503  typedef struct
3504  {
3505  MultiXactMember *members;
3506  int nmembers;
3507  int iter;
3508  } mxact;
3510  mxact *multi;
3511  FuncCallContext *funccxt;
3512 
3513  if (mxid < FirstMultiXactId)
3514  ereport(ERROR,
3515  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3516  errmsg("invalid MultiXactId: %u", mxid)));
3517 
3518  if (SRF_IS_FIRSTCALL())
3519  {
3520  MemoryContext oldcxt;
3521  TupleDesc tupdesc;
3522 
3523  funccxt = SRF_FIRSTCALL_INIT();
3524  oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3525 
3526  multi = palloc(sizeof(mxact));
3527  /* no need to allow for old values here */
3528  multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3529  false);
3530  multi->iter = 0;
3531 
3532  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3533  elog(ERROR, "return type must be a row type");
3534  funccxt->tuple_desc = tupdesc;
3535  funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3536  funccxt->user_fctx = multi;
3537 
3538  MemoryContextSwitchTo(oldcxt);
3539  }
3540 
3541  funccxt = SRF_PERCALL_SETUP();
3542  multi = (mxact *) funccxt->user_fctx;
3543 
3544  while (multi->iter < multi->nmembers)
3545  {
3546  HeapTuple tuple;
3547  char *values[2];
3548 
3549  values[0] = psprintf("%u", multi->members[multi->iter].xid);
3550  values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3551 
3552  tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3553 
3554  multi->iter++;
3555  pfree(values[0]);
3556  SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3557  }
3558 
3559  SRF_RETURN_DONE(funccxt);
3560 }
static Datum values[MAXATTR]
Definition: bootstrap.c:150
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2222
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2173
#define PG_GETARG_TRANSACTIONID(n)
Definition: fmgr.h:279
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
while(p+4<=pend)
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
MemoryContextSwitchTo(old_ctx)
void * user_fctx
Definition: funcapi.h:82
AttInMetadata * attinmeta
Definition: funcapi.h:91
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112

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

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1842 of file multixact.c.

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

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

Referenced by PrepareTransaction().

◆ PreviousMultiXactId()

static MultiXactId PreviousMultiXactId ( MultiXactId  multi)
inlinestatic

Definition at line 220 of file multixact.c.

221 {
222  return multi == FirstMultiXactId ? MaxMultiXactId : multi - 1;
223 }
#define MaxMultiXactId
Definition: multixact.h:26

References FirstMultiXactId, and MaxMultiXactId.

Referenced by PerformOffsetsTruncation().

◆ ReadMultiXactCounts()

static bool ReadMultiXactCounts ( uint32 multixacts,
MultiXactOffset members 
)
static

Definition at line 2918 of file multixact.c.

2919 {
2920  MultiXactOffset nextOffset;
2921  MultiXactOffset oldestOffset;
2922  MultiXactId oldestMultiXactId;
2923  MultiXactId nextMultiXactId;
2924  bool oldestOffsetKnown;
2925 
2926  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2927  nextOffset = MultiXactState->nextOffset;
2928  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2929  nextMultiXactId = MultiXactState->nextMXact;
2930  oldestOffset = MultiXactState->oldestOffset;
2931  oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2932  LWLockRelease(MultiXactGenLock);
2933 
2934  if (!oldestOffsetKnown)
2935  return false;
2936 
2937  *members = nextOffset - oldestOffset;
2938  *multixacts = nextMultiXactId - oldestMultiXactId;
2939  return true;
2940 }

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

791 {
792  LWLockAcquire(MultiXactGenLock, LW_SHARED);
795  LWLockRelease(MultiXactGenLock);
796 
797  if (*oldest < FirstMultiXactId)
798  *oldest = FirstMultiXactId;
799  if (*next < FirstMultiXactId)
801 }
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 770 of file multixact.c.

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

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

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

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

Referenced by multixact_redo(), and MultiXactIdCreateFromMembers().

◆ SetMultiXactIdLimit()

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

Definition at line 2354 of file multixact.c.

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

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

2706 {
2707  MultiXactId oldestMultiXactId;
2708  MultiXactId nextMXact;
2709  MultiXactOffset oldestOffset = 0; /* placate compiler */
2710  MultiXactOffset prevOldestOffset;
2711  MultiXactOffset nextOffset;
2712  bool oldestOffsetKnown = false;
2713  bool prevOldestOffsetKnown;
2714  MultiXactOffset offsetStopLimit = 0;
2715  MultiXactOffset prevOffsetStopLimit;
2716 
2717  /*
2718  * NB: Have to prevent concurrent truncation, we might otherwise try to
2719  * lookup an oldestMulti that's concurrently getting truncated away.
2720  */
2721  LWLockAcquire(MultiXactTruncationLock, LW_SHARED);
2722 
2723  /* Read relevant fields from shared memory. */
2724  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2725  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2726  nextMXact = MultiXactState->nextMXact;
2727  nextOffset = MultiXactState->nextOffset;
2728  prevOldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2729  prevOldestOffset = MultiXactState->oldestOffset;
2730  prevOffsetStopLimit = MultiXactState->offsetStopLimit;
2732  LWLockRelease(MultiXactGenLock);
2733 
2734  /*
2735  * Determine the offset of the oldest multixact. Normally, we can read
2736  * the offset from the multixact itself, but there's an important special
2737  * case: if there are no multixacts in existence at all, oldestMXact
2738  * obviously can't point to one. It will instead point to the multixact
2739  * ID that will be assigned the next time one is needed.
2740  */
2741  if (oldestMultiXactId == nextMXact)
2742  {
2743  /*
2744  * When the next multixact gets created, it will be stored at the next
2745  * offset.
2746  */
2747  oldestOffset = nextOffset;
2748  oldestOffsetKnown = true;
2749  }
2750  else
2751  {
2752  /*
2753  * Figure out where the oldest existing multixact's offsets are
2754  * stored. Due to bugs in early release of PostgreSQL 9.3.X and 9.4.X,
2755  * the supposedly-earliest multixact might not really exist. We are
2756  * careful not to fail in that case.
2757  */
2758  oldestOffsetKnown =
2759  find_multixact_start(oldestMultiXactId, &oldestOffset);
2760 
2761  if (oldestOffsetKnown)
2762  ereport(DEBUG1,
2763  (errmsg_internal("oldest MultiXactId member is at offset %u",
2764  oldestOffset)));
2765  else
2766  ereport(LOG,
2767  (errmsg("MultiXact member wraparound protections are disabled because oldest checkpointed MultiXact %u does not exist on disk",
2768  oldestMultiXactId)));
2769  }
2770 
2771  LWLockRelease(MultiXactTruncationLock);
2772 
2773  /*
2774  * If we can, compute limits (and install them MultiXactState) to prevent
2775  * overrun of old data in the members SLRU area. We can only do so if the
2776  * oldest offset is known though.
2777  */
2778  if (oldestOffsetKnown)
2779  {
2780  /* move back to start of the corresponding segment */
2781  offsetStopLimit = oldestOffset - (oldestOffset %
2783 
2784  /* always leave one segment before the wraparound point */
2785  offsetStopLimit -= (MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT);
2786 
2787  if (!prevOldestOffsetKnown && !is_startup)
2788  ereport(LOG,
2789  (errmsg("MultiXact member wraparound protections are now enabled")));
2790 
2791  ereport(DEBUG1,
2792  (errmsg_internal("MultiXact member stop limit is now %u based on MultiXact %u",
2793  offsetStopLimit, oldestMultiXactId)));
2794  }
2795  else if (prevOldestOffsetKnown)
2796  {
2797  /*
2798  * If we failed to get the oldest offset this time, but we have a
2799  * value from a previous pass through this function, use the old
2800  * values rather than automatically forcing an emergency autovacuum
2801  * cycle again.
2802  */
2803  oldestOffset = prevOldestOffset;
2804  oldestOffsetKnown = true;
2805  offsetStopLimit = prevOffsetStopLimit;
2806  }
2807 
2808  /* Install the computed values */
2809  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2810  MultiXactState->oldestOffset = oldestOffset;
2811  MultiXactState->oldestOffsetKnown = oldestOffsetKnown;
2812  MultiXactState->offsetStopLimit = offsetStopLimit;
2813  LWLockRelease(MultiXactGenLock);
2814 
2815  /*
2816  * Do we need an emergency autovacuum? If we're not sure, assume yes.
2817  */
2818  return !oldestOffsetKnown ||
2819  (nextOffset - oldestOffset > MULTIXACT_MEMBER_SAFE_THRESHOLD);
2820 }
#define LOG
Definition: elog.h:31
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition: multixact.c:2880

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

3018 {
3019  mxtruncinfo *trunc = (mxtruncinfo *) data;
3020 
3021  if (trunc->earliestExistingPage == -1 ||
3022  ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
3023  {
3024  trunc->earliestExistingPage = segpage;
3025  }
3026 
3027  return false; /* keep going */
3028 }
const void * data
tree ctl
Definition: radixtree.h:1853
int64 earliestExistingPage
Definition: multixact.c:3009

References ctl, data, and mxtruncinfo::earliestExistingPage.

Referenced by TruncateMultiXact().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2145 of file multixact.c.

2146 {
2149  int64 pageno;
2150 
2151  /*
2152  * Initialize offset's idea of the latest page number.
2153  */
2154  pageno = MultiXactIdToOffsetPage(multi);
2155  pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2156  pageno);
2157 
2158  /*
2159  * Initialize member's idea of the latest page number.
2160  */
2161  pageno = MXOffsetToMemberPage(offset);
2162  pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
2163  pageno);
2164 }

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

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

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

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

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

3363 {
3364  XLogRecPtr recptr;
3365  xl_multixact_truncate xlrec;
3366 
3367  xlrec.oldestMultiDB = oldestMultiDB;
3368 
3369  xlrec.startTruncOff = startTruncOff;
3370  xlrec.endTruncOff = endTruncOff;
3371 
3372  xlrec.startTruncMemb = startTruncMemb;
3373  xlrec.endTruncMemb = endTruncMemb;
3374 
3375  XLogBeginInsert();
3376  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3377  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3378  XLogFlush(recptr);
3379 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2789
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 3346 of file multixact.c.

3347 {
3348  XLogBeginInsert();
3349  XLogRegisterData((char *) (&pageno), sizeof(pageno));
3350  (void) XLogInsert(RM_MULTIXACT_ID, info);
3351 }

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

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

◆ ZeroMultiXactMemberPage()

static int ZeroMultiXactMemberPage ( int64  pageno,
bool  writeXlog 
)
static

Definition at line 2082 of file multixact.c.

2083 {
2084  int slotno;
2085 
2086  slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
2087 
2088  if (writeXlog)
2090 
2091  return slotno;
2092 }
static void WriteMZeroPageXlogRec(int64 pageno, uint8 info)
Definition: multixact.c:3346
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:375

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

2067 {
2068  int slotno;
2069 
2070  slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
2071 
2072  if (writeXlog)
2074 
2075  return slotno;
2076 }

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

◆ MultiXactOffsetCtlData

SlruCtlData MultiXactOffsetCtlData
static

Definition at line 228 of file multixact.c.

◆ MultiXactState

◆ MXactCache

◆ MXactContext

MemoryContext MXactContext = NULL
static

Definition at line 371 of file multixact.c.

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

◆ OldestMemberMXactId

◆ OldestVisibleMXactId