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/xloginsert.h"
#include "access/xlogutils.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "funcapi.h"
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
#include "utils/guc_hooks.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
Include dependency graph for multixact.c:

Go to the source code of this file.

Data Structures

struct  MultiXactStateData
 
struct  mXactCacheEnt
 
struct  mxtruncinfo
 

Macros

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))
 
#define MultiXactIdToOffsetPage(xid)    ((xid) / (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)
 
#define MultiXactIdToOffsetEntry(xid)    ((xid) % (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)
 
#define MultiXactIdToOffsetSegment(xid)   (MultiXactIdToOffsetPage(xid) / SLRU_PAGES_PER_SEGMENT)
 
#define MXACT_MEMBER_BITS_PER_XACT   8
 
#define MXACT_MEMBER_FLAGS_PER_BYTE   1
 
#define MXACT_MEMBER_XACT_BITMASK   ((1 << MXACT_MEMBER_BITS_PER_XACT) - 1)
 
#define MULTIXACT_FLAGBYTES_PER_GROUP   4
 
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP    (MULTIXACT_FLAGBYTES_PER_GROUP * MXACT_MEMBER_FLAGS_PER_BYTE)
 
#define MULTIXACT_MEMBERGROUP_SIZE    (sizeof(TransactionId) * MULTIXACT_MEMBERS_PER_MEMBERGROUP + MULTIXACT_FLAGBYTES_PER_GROUP)
 
#define MULTIXACT_MEMBERGROUPS_PER_PAGE   (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)
 
#define MULTIXACT_MEMBERS_PER_PAGE    (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)
 
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE    ((uint32) ((0xFFFFFFFF % MULTIXACT_MEMBERS_PER_PAGE) + 1))
 
#define MXOffsetToMemberPage(xid)   ((xid) / (TransactionId) MULTIXACT_MEMBERS_PER_PAGE)
 
#define MXOffsetToMemberSegment(xid)   (MXOffsetToMemberPage(xid) / SLRU_PAGES_PER_SEGMENT)
 
#define MXOffsetToFlagsOffset(xid)
 
#define MXOffsetToFlagsBitShift(xid)
 
#define MXOffsetToMemberOffset(xid)
 
#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)
 
#define MULTIXACT_MEMBER_DANGER_THRESHOLD    (MaxMultiXactOffset - MaxMultiXactOffset / 4)
 
#define PreviousMultiXactId(xid)    ((xid) == FirstMultiXactId ? MaxMultiXactId : (xid) - 1)
 
#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)
 
#define MultiXactMemberCtl   (&MultiXactMemberCtlData)
 
#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)
 
#define MAX_CACHE_ENTRIES   256
 
#define debug_elog2(a, b)
 
#define debug_elog3(a, b, c)
 
#define debug_elog4(a, b, c, d)
 
#define debug_elog5(a, b, c, d, e)
 
#define debug_elog6(a, b, c, d, e, f)
 
#define OFFSET_WARN_SEGMENTS   20
 
#define SHARED_MULTIXACT_STATE_SIZE
 

Typedefs

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

Functions

static void MultiXactIdSetOldestVisible (void)
 
static void RecordNewMultiXact (MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
 
static MultiXactId GetNewMultiXactId (int nmembers, MultiXactOffset *offset)
 
static int mxactMemberComparator (const void *arg1, const void *arg2)
 
static MultiXactId mXactCacheGetBySet (int nmembers, MultiXactMember *members)
 
static int mXactCacheGetById (MultiXactId multi, MultiXactMember **members)
 
static void mXactCachePut (MultiXactId multi, int nmembers, MultiXactMember *members)
 
static char * mxstatus_to_string (MultiXactStatus status)
 
static int ZeroMultiXactOffsetPage (int64 pageno, bool writeXlog)
 
static int ZeroMultiXactMemberPage (int64 pageno, bool writeXlog)
 
static bool MultiXactOffsetPagePrecedes (int64 page1, int64 page2)
 
static bool MultiXactMemberPagePrecedes (int64 page1, int64 page2)
 
static bool MultiXactOffsetPrecedes (MultiXactOffset offset1, MultiXactOffset offset2)
 
static void ExtendMultiXactOffset (MultiXactId multi)
 
static void ExtendMultiXactMember (MultiXactOffset offset, int nmembers)
 
static bool MultiXactOffsetWouldWrap (MultiXactOffset boundary, MultiXactOffset start, uint32 distance)
 
static bool SetOffsetVacuumLimit (bool is_startup)
 
static bool find_multixact_start (MultiXactId multi, MultiXactOffset *result)
 
static void WriteMZeroPageXlogRec (int64 pageno, uint8 info)
 
static void WriteMTruncateXlogRec (Oid oldestMultiDB, MultiXactId startTruncOff, MultiXactId endTruncOff, MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
 
MultiXactId MultiXactIdCreate (TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
 
MultiXactId MultiXactIdExpand (MultiXactId multi, TransactionId xid, MultiXactStatus status)
 
bool MultiXactIdIsRunning (MultiXactId multi, bool isLockOnly)
 
void MultiXactIdSetOldestMember (void)
 
MultiXactId ReadNextMultiXactId (void)
 
void ReadMultiXactIdRange (MultiXactId *oldest, MultiXactId *next)
 
MultiXactId MultiXactIdCreateFromMembers (int nmembers, MultiXactMember *members)
 
int GetMultiXactIdMembers (MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
 
char * mxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)
 
void AtEOXact_MultiXact (void)
 
void AtPrepare_MultiXact (void)
 
void PostPrepare_MultiXact (TransactionId xid)
 
void multixact_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postcommit (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postabort (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
Size MultiXactShmemSize (void)
 
void MultiXactShmemInit (void)
 
bool check_multixact_offset_buffers (int *newval, void **extra, GucSource source)
 
bool check_multixact_member_buffers (int *newval, void **extra, GucSource source)
 
void BootStrapMultiXact (void)
 
static void MaybeExtendOffsetSlru (void)
 
void StartupMultiXact (void)
 
void TrimMultiXact (void)
 
void MultiXactGetCheckptMulti (bool is_shutdown, MultiXactId *nextMulti, MultiXactOffset *nextMultiOffset, MultiXactId *oldestMulti, Oid *oldestMultiDB)
 
void CheckPointMultiXact (void)
 
void MultiXactSetNextMXact (MultiXactId nextMulti, MultiXactOffset nextMultiOffset)
 
void SetMultiXactIdLimit (MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
 
void MultiXactAdvanceNextMXact (MultiXactId minMulti, MultiXactOffset minMultiOffset)
 
void MultiXactAdvanceOldest (MultiXactId oldestMulti, Oid oldestMultiDB)
 
MultiXactId GetOldestMultiXactId (void)
 
static bool ReadMultiXactCounts (uint32 *multixacts, MultiXactOffset *members)
 
int MultiXactMemberFreezeThreshold (void)
 
static bool SlruScanDirCbFindEarliest (SlruCtl ctl, char *filename, int64 segpage, void *data)
 
static void PerformMembersTruncation (MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
 
static void PerformOffsetsTruncation (MultiXactId oldestMulti, MultiXactId newOldestMulti)
 
void TruncateMultiXact (MultiXactId newOldestMulti, Oid newOldestMultiDB)
 
bool MultiXactIdPrecedes (MultiXactId multi1, MultiXactId multi2)
 
bool MultiXactIdPrecedesOrEquals (MultiXactId multi1, MultiXactId multi2)
 
void multixact_redo (XLogReaderState *record)
 
Datum pg_get_multixact_members (PG_FUNCTION_ARGS)
 
int multixactoffsetssyncfiletag (const FileTag *ftag, char *path)
 
int multixactmemberssyncfiletag (const FileTag *ftag, char *path)
 

Variables

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

Macro Definition Documentation

◆ debug_elog2

#define debug_elog2 (   a,
  b 
)

Definition at line 334 of file multixact.c.

◆ debug_elog3

#define debug_elog3 (   a,
  b,
  c 
)

Definition at line 335 of file multixact.c.

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

Definition at line 336 of file multixact.c.

◆ debug_elog5

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

Definition at line 337 of file multixact.c.

◆ debug_elog6

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

Definition at line 338 of file multixact.c.

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

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

◆ MaxOldestSlot

#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)

Definition at line 290 of file multixact.c.

◆ MULTIXACT_FLAGBYTES_PER_GROUP

#define MULTIXACT_FLAGBYTES_PER_GROUP   4

Definition at line 136 of file multixact.c.

◆ MULTIXACT_MEMBER_DANGER_THRESHOLD

#define MULTIXACT_MEMBER_DANGER_THRESHOLD    (MaxMultiXactOffset - MaxMultiXactOffset / 4)

Definition at line 179 of file multixact.c.

◆ MULTIXACT_MEMBER_SAFE_THRESHOLD

#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)

Definition at line 178 of file multixact.c.

◆ MULTIXACT_MEMBERGROUP_SIZE

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

Definition at line 140 of file multixact.c.

◆ MULTIXACT_MEMBERGROUPS_PER_PAGE

#define MULTIXACT_MEMBERGROUPS_PER_PAGE   (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)

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

◆ MULTIXACT_MEMBERS_PER_PAGE

#define MULTIXACT_MEMBERS_PER_PAGE    (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)

Definition at line 143 of file multixact.c.

◆ MULTIXACT_OFFSETS_PER_PAGE

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))

Definition at line 110 of file multixact.c.

◆ MultiXactIdToOffsetEntry

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

Definition at line 114 of file multixact.c.

◆ MultiXactIdToOffsetPage

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

Definition at line 112 of file multixact.c.

◆ MultiXactIdToOffsetSegment

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

Definition at line 116 of file multixact.c.

◆ MultiXactMemberCtl

#define MultiXactMemberCtl   (&MultiXactMemberCtlData)

Definition at line 192 of file multixact.c.

◆ MultiXactOffsetCtl

#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)

Definition at line 191 of file multixact.c.

◆ MXACT_MEMBER_BITS_PER_XACT

#define MXACT_MEMBER_BITS_PER_XACT   8

Definition at line 131 of file multixact.c.

◆ MXACT_MEMBER_FLAGS_PER_BYTE

#define MXACT_MEMBER_FLAGS_PER_BYTE   1

Definition at line 132 of file multixact.c.

◆ MXACT_MEMBER_XACT_BITMASK

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

Definition at line 133 of file multixact.c.

◆ MXOffsetToFlagsBitShift

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

Definition at line 168 of file multixact.c.

◆ MXOffsetToFlagsOffset

#define MXOffsetToFlagsOffset (   xid)
Value:

Definition at line 164 of file multixact.c.

◆ MXOffsetToMemberOffset

#define MXOffsetToMemberOffset (   xid)
Value:
#define MULTIXACT_FLAGBYTES_PER_GROUP
Definition: multixact.c:136
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:164

Definition at line 173 of file multixact.c.

◆ MXOffsetToMemberPage

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

Definition at line 160 of file multixact.c.

◆ MXOffsetToMemberSegment

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

Definition at line 161 of file multixact.c.

◆ OFFSET_WARN_SEGMENTS

#define OFFSET_WARN_SEGMENTS   20

◆ PreviousMultiXactId

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

Definition at line 182 of file multixact.c.

◆ SHARED_MULTIXACT_STATE_SIZE

#define SHARED_MULTIXACT_STATE_SIZE
Value:
add_size(offsetof(MultiXactStateData, perBackendXactIds), \
TransactionId MultiXactId
Definition: c.h:649
#define MaxOldestSlot
Definition: multixact.c:290
Size add_size(Size s1, Size s2)
Definition: shmem.c:494
Size mul_size(Size s1, Size s2)
Definition: shmem.c:511

Typedef Documentation

◆ MultiXactStateData

◆ mXactCacheEnt

typedef struct mXactCacheEnt mXactCacheEnt

◆ mxtruncinfo

typedef struct mxtruncinfo mxtruncinfo

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1745 of file multixact.c.

1746 {
1747  /*
1748  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1749  * which should only be valid while within a transaction.
1750  *
1751  * We assume that storing a MultiXactId is atomic and so we need not take
1752  * MultiXactGenLock to do this.
1753  */
1756 
1757  /*
1758  * Discard the local MultiXactId cache. Since MXactContext was created as
1759  * a child of TopTransactionContext, we needn't delete it explicitly.
1760  */
1761  MXactContext = NULL;
1763 }
ProcNumber MyProcNumber
Definition: globals.c:86
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:325
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:295
static dclist_head MXactCache
Definition: multixact.c:324
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:294
#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 1773 of file multixact.c.

1774 {
1775  MultiXactId myOldestMember = OldestMemberMXactId[MyProcNumber];
1776 
1777  if (MultiXactIdIsValid(myOldestMember))
1779  &myOldestMember, sizeof(MultiXactId));
1780 }
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1283
#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 1970 of file multixact.c.

1971 {
1972  int slotno;
1973  LWLock *lock;
1974 
1976  LWLockAcquire(lock, LW_EXCLUSIVE);
1977 
1978  /* Create and zero the first page of the offsets log */
1979  slotno = ZeroMultiXactOffsetPage(0, false);
1980 
1981  /* Make sure it's written out */
1983  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1984 
1985  LWLockRelease(lock);
1986 
1988  LWLockAcquire(lock, LW_EXCLUSIVE);
1989 
1990  /* Create and zero the first page of the members log */
1991  slotno = ZeroMultiXactMemberPage(0, false);
1992 
1993  /* Make sure it's written out */
1995  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1996 
1997  LWLockRelease(lock);
1998 }
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1175
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1788
@ LW_EXCLUSIVE
Definition: lwlock.h:116
static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2026
#define MultiXactMemberCtl
Definition: multixact.c:192
#define MultiXactOffsetCtl
Definition: multixact.c:191
static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
Definition: multixact.c:2010
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:715
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:179
Definition: lwlock.h:41

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

Referenced by BootStrapXLOG().

◆ check_multixact_member_buffers()

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

Definition at line 1959 of file multixact.c.

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

References check_slru_buffers(), and newval.

◆ check_multixact_offset_buffers()

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

Definition at line 1950 of file multixact.c.

1951 {
1952  return check_slru_buffers("multixact_offset_buffers", newval);
1953 }

References check_slru_buffers(), and newval.

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2240 of file multixact.c.

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

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ ExtendMultiXactMember()

static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2521 of file multixact.c.

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

2490 {
2491  int64 pageno;
2492  LWLock *lock;
2493 
2494  /*
2495  * No work except at first MultiXactId of a page. But beware: just after
2496  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2497  */
2498  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2499  multi != FirstMultiXactId)
2500  return;
2501 
2502  pageno = MultiXactIdToOffsetPage(multi);
2503  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2504 
2505  LWLockAcquire(lock, LW_EXCLUSIVE);
2506 
2507  /* Zero the page and make an XLOG entry about it */
2508  ZeroMultiXactOffsetPage(pageno, true);
2509 
2510  LWLockRelease(lock);
2511 }
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:114
#define MultiXactIdToOffsetPage(xid)
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 2824 of file multixact.c.

2825 {
2826  MultiXactOffset offset;
2827  int64 pageno;
2828  int entryno;
2829  int slotno;
2830  MultiXactOffset *offptr;
2831 
2833 
2834  pageno = MultiXactIdToOffsetPage(multi);
2835  entryno = MultiXactIdToOffsetEntry(multi);
2836 
2837  /*
2838  * Write out dirty data, so PhysicalPageExists can work correctly.
2839  */
2842 
2844  return false;
2845 
2846  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2847  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2848  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2849  offptr += entryno;
2850  offset = *offptr;
2852 
2853  *result = offset;
2854  return true;
2855 }
uint32 MultiXactOffset
Definition: c.h:651
static MultiXactStateData * MultiXactState
Definition: multixact.c:293
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition: slru.c:592
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int64 pageno)
Definition: slru.c:729

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

Referenced by SetOffsetVacuumLimit(), and TruncateMultiXact().

◆ GetMultiXactIdMembers()

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

Definition at line 1241 of file multixact.c.

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

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

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

◆ GetNewMultiXactId()

static MultiXactId GetNewMultiXactId ( int  nmembers,
MultiXactOffset offset 
)
static

Definition at line 974 of file multixact.c.

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

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

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

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

2055 {
2056  int64 pageno;
2057  LWLock *lock;
2058 
2060  lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
2061 
2062  LWLockAcquire(lock, LW_EXCLUSIVE);
2063 
2065  {
2066  int slotno;
2067 
2068  /*
2069  * Fortunately for us, SimpleLruWritePage is already prepared to deal
2070  * with creating a new segment file even if the page we're writing is
2071  * not the first in it, so this is enough.
2072  */
2073  slotno = ZeroMultiXactOffsetPage(pageno, false);
2075  }
2076 
2077  LWLockRelease(lock);
2078 }

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

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

1874 {
1875  multixact_twophase_postcommit(xid, info, recdata, len);
1876 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1857
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 1857 of file multixact.c.

1859 {
1860  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, true);
1861 
1862  Assert(len == sizeof(MultiXactId));
1863 
1864  OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1865 }
int ProcNumber
Definition: procnumber.h:24
ProcNumber TwoPhaseGetDummyProcNumber(TransactionId xid, bool lock_held)
Definition: twophase.c:906

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

1838 {
1839  ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(xid, false);
1840  MultiXactId oldestMember;
1841 
1842  /*
1843  * Get the oldest member XID from the state file record, and set it in the
1844  * OldestMemberMXactId slot reserved for this prepared transaction.
1845  */
1846  Assert(len == sizeof(MultiXactId));
1847  oldestMember = *((MultiXactId *) recdata);
1848 
1849  OldestMemberMXactId[dummyProcNumber] = oldestMember;
1850 }

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2447 of file multixact.c.

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

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

2473 {
2474  Assert(InRecovery);
2475 
2477  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2478 }
bool InRecovery
Definition: xlogutils.c:53

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

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

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

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

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

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

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

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

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

3260 {
3261  int32 diff = (int32) (multi1 - multi2);
3262 
3263  return (diff <= 0);
3264 }

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

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

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

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

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

Referenced by GetMultiXactIdMembers().

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2914 of file multixact.c.

2915 {
2916  MultiXactOffset members;
2917  uint32 multixacts;
2918  uint32 victim_multixacts;
2919  double fraction;
2920 
2921  /* If we can't determine member space utilization, assume the worst. */
2922  if (!ReadMultiXactCounts(&multixacts, &members))
2923  return 0;
2924 
2925  /* If member space utilization is low, no special action is required. */
2926  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2928 
2929  /*
2930  * Compute a target for relminmxid advancement. The number of multixacts
2931  * we try to eliminate from the system is based on how far we are past
2932  * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2933  */
2934  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2936  victim_multixacts = multixacts * fraction;
2937 
2938  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2939  if (victim_multixacts > multixacts)
2940  return 0;
2941  return multixacts - victim_multixacts;
2942 }
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:128
static bool ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
Definition: multixact.c:2862
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:179

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

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

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 3225 of file multixact.c.

3226 {
3227  MultiXactOffset offset1;
3228  MultiXactOffset offset2;
3229 
3230  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3231  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3232 
3233  return (MultiXactOffsetPrecedes(offset1, offset2) &&
3234  MultiXactOffsetPrecedes(offset1,
3235  offset2 + MULTIXACT_MEMBERS_PER_PAGE - 1));
3236 }

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3512 of file multixact.c.

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

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 3205 of file multixact.c.

3206 {
3207  MultiXactId multi1;
3208  MultiXactId multi2;
3209 
3210  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3211  multi1 += FirstMultiXactId + 1;
3212  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3213  multi2 += FirstMultiXactId + 1;
3214 
3215  return (MultiXactIdPrecedes(multi1, multi2) &&
3216  MultiXactIdPrecedes(multi1,
3217  multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
3218 }
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:110

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

◆ MultiXactOffsetPrecedes()

static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3271 of file multixact.c.

3272 {
3273  int32 diff = (int32) (offset1 - offset2);
3274 
3275  return (diff < 0);
3276 }

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3503 of file multixact.c.

3504 {
3505  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3506 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactOffsetWouldWrap()

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

Definition at line 2776 of file multixact.c.

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

Referenced by GetNewMultiXactId().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2264 of file multixact.c.

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

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

1902 {
1903  bool found;
1904 
1905  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1906 
1909 
1911  "multixact_offset", multixact_offset_buffers, 0,
1912  "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1915  false);
1918  "multixact_member", multixact_member_buffers, 0,
1919  "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1922  false);
1923  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1924 
1925  /* Initialize our shared state struct */
1926  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1928  &found);
1929  if (!IsUnderPostmaster)
1930  {
1931  Assert(!found);
1932 
1933  /* Make sure we zero out the per-backend state */
1935  }
1936  else
1937  Assert(found);
1938 
1939  /*
1940  * Set up array pointers.
1941  */
1944 }
#define MemSet(start, val, len)
Definition: c.h:1007
int multixact_offset_buffers
Definition: globals.c:164
int multixact_member_buffers
Definition: globals.c:163
@ LWTRANCHE_MULTIXACTOFFSET_SLRU
Definition: lwlock.h:214
@ LWTRANCHE_MULTIXACTMEMBER_SLRU
Definition: lwlock.h:213
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:185
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:184
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3225
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:3205
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:388
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition: slru.c:238
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:203
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:284
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40

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

Referenced by CreateOrAttachShmemStructs().

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1884 of file multixact.c.

1885 {
1886  Size size;
1887 
1888  /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1889 #define SHARED_MULTIXACT_STATE_SIZE \
1890  add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1891  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1892 
1896 
1897  return size;
1898 }
size_t Size
Definition: c.h:592
static pg_noinline void Size size
Definition: slab.c:607
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:184

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

Referenced by CalculateShmemSize().

◆ mXactCacheGetById()

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

Definition at line 1599 of file multixact.c.

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

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

1557 {
1558  dlist_iter iter;
1559 
1560  debug_elog3(DEBUG2, "CacheGet: looking for %s",
1561  mxid_to_string(InvalidMultiXactId, nmembers, members));
1562 
1563  /* sort the array so comparison is easy */
1564  qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1565 
1566  dclist_foreach(iter, &MXactCache)
1567  {
1569  iter.cur);
1570 
1571  if (entry->nmembers != nmembers)
1572  continue;
1573 
1574  /*
1575  * We assume the cache entries are sorted, and that the unused bits in
1576  * "status" are zeroed.
1577  */
1578  if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1579  {
1580  debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1582  return entry->multi;
1583  }
1584  }
1585 
1586  debug_elog2(DEBUG2, "CacheGet: not found :-(");
1587  return InvalidMultiXactId;
1588 }
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition: multixact.c:1526
#define qsort(a, b, c, d)
Definition: port.h:449

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

Referenced by MultiXactIdCreateFromMembers().

◆ mXactCachePut()

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

Definition at line 1646 of file multixact.c.

1647 {
1648  mXactCacheEnt *entry;
1649 
1650  debug_elog3(DEBUG2, "CachePut: storing %s",
1651  mxid_to_string(multi, nmembers, members));
1652 
1653  if (MXactContext == NULL)
1654  {
1655  /* The cache only lives as long as the current transaction */
1656  debug_elog2(DEBUG2, "CachePut: initializing memory context");
1658  "MultiXact cache context",
1660  }
1661 
1662  entry = (mXactCacheEnt *)
1664  offsetof(mXactCacheEnt, members) +
1665  nmembers * sizeof(MultiXactMember));
1666 
1667  entry->multi = multi;
1668  entry->nmembers = nmembers;
1669  memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1670 
1671  /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1672  qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1673 
1674  dclist_push_head(&MXactCache, &entry->node);
1676  {
1677  dlist_node *node;
1678 
1679  node = dclist_tail_node(&MXactCache);
1681 
1682  entry = dclist_container(mXactCacheEnt, node, node);
1683  debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1684  entry->multi);
1685 
1686  pfree(entry);
1687  }
1688 }
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:146
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1066
#define AllocSetContextCreate
Definition: memutils.h:128
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:162
#define MAX_CACHE_ENTRIES
Definition: multixact.c:323
dlist_node node
Definition: multixact.c:319

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

1527 {
1528  MultiXactMember member1 = *(const MultiXactMember *) arg1;
1529  MultiXactMember member2 = *(const MultiXactMember *) arg2;
1530 
1531  if (member1.xid > member2.xid)
1532  return 1;
1533  if (member1.xid < member2.xid)
1534  return -1;
1535  if (member1.status > member2.status)
1536  return 1;
1537  if (member1.status < member2.status)
1538  return -1;
1539  return 0;
1540 }

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

1715 {
1716  static char *str = NULL;
1718  int i;
1719 
1720  if (str != NULL)
1721  pfree(str);
1722 
1723  initStringInfo(&buf);
1724 
1725  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1726  mxstatus_to_string(members[0].status));
1727 
1728  for (i = 1; i < nmembers; i++)
1729  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1730  mxstatus_to_string(members[i].status));
1731 
1732  appendStringInfoChar(&buf, ']');
1734  pfree(buf.data);
1735  return str;
1736 }
MemoryContext TopMemoryContext
Definition: mcxt.c:141
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1567
static char * buf
Definition: pg_test_fsync.c:73
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

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

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

◆ mxstatus_to_string()

static char * mxstatus_to_string ( MultiXactStatus  status)
static

Definition at line 1691 of file multixact.c.

1692 {
1693  switch (status)
1694  {
1696  return "keysh";
1698  return "sh";
1700  return "fornokeyupd";
1702  return "forupd";
1704  return "nokeyupd";
1705  case MultiXactStatusUpdate:
1706  return "upd";
1707  default:
1708  elog(ERROR, "unrecognized multixact status %d", status);
1709  return "";
1710  }
1711 }
@ 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 2977 of file multixact.c.

2978 {
2979  const int maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
2980  int startsegment = MXOffsetToMemberSegment(oldestOffset);
2981  int endsegment = MXOffsetToMemberSegment(newOldestOffset);
2982  int segment = startsegment;
2983 
2984  /*
2985  * Delete all the segments but the last one. The last segment can still
2986  * contain, possibly partially, valid data.
2987  */
2988  while (segment != endsegment)
2989  {
2990  elog(DEBUG2, "truncating multixact members segment %x", segment);
2992 
2993  /* move to next segment, handling wraparound correctly */
2994  if (segment == maxsegment)
2995  segment = 0;
2996  else
2997  segment += 1;
2998  }
2999 }
void SlruDeleteSegment(SlruCtl ctl, int64 segno)
Definition: slru.c:1509

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

Referenced by multixact_redo(), and TruncateMultiXact().

◆ PerformOffsetsTruncation()

static void PerformOffsetsTruncation ( MultiXactId  oldestMulti,
MultiXactId  newOldestMulti 
)
static

Definition at line 3005 of file multixact.c.

3006 {
3007  /*
3008  * We step back one multixact to avoid passing a cutoff page that hasn't
3009  * been created yet in the rare case that oldestMulti would be the first
3010  * item on a page and oldestMulti == nextMulti. In that case, if we
3011  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
3012  * detection.
3013  */
3015  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
3016 }
#define PreviousMultiXactId(xid)
Definition: multixact.c:182
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition: slru.c:1391

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

Referenced by multixact_redo(), and TruncateMultiXact().

◆ pg_get_multixact_members()

Datum pg_get_multixact_members ( PG_FUNCTION_ARGS  )

Definition at line 3438 of file multixact.c.

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

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

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1787 of file multixact.c.

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

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

Referenced by PrepareTransaction().

◆ ReadMultiXactCounts()

static bool ReadMultiXactCounts ( uint32 multixacts,
MultiXactOffset members 
)
static

Definition at line 2862 of file multixact.c.

2863 {
2864  MultiXactOffset nextOffset;
2865  MultiXactOffset oldestOffset;
2866  MultiXactId oldestMultiXactId;
2867  MultiXactId nextMultiXactId;
2868  bool oldestOffsetKnown;
2869 
2870  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2871  nextOffset = MultiXactState->nextOffset;
2872  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2873  nextMultiXactId = MultiXactState->nextMXact;
2874  oldestOffset = MultiXactState->oldestOffset;
2875  oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2876  LWLockRelease(MultiXactGenLock);
2877 
2878  if (!oldestOffsetKnown)
2879  return false;
2880 
2881  *members = nextOffset - oldestOffset;
2882  *multixacts = nextMultiXactId - oldestMultiXactId;
2883  return true;
2884 }

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

745 {
746  LWLockAcquire(MultiXactGenLock, LW_SHARED);
749  LWLockRelease(MultiXactGenLock);
750 
751  if (*oldest < FirstMultiXactId)
752  *oldest = FirstMultiXactId;
753  if (*next < FirstMultiXactId)
755 }
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 724 of file multixact.c.

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

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

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

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

Referenced by multixact_redo(), and MultiXactIdCreateFromMembers().

◆ SetMultiXactIdLimit()

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

Definition at line 2298 of file multixact.c.

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

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

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

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

2955 {
2956  mxtruncinfo *trunc = (mxtruncinfo *) data;
2957 
2958  if (trunc->earliestExistingPage == -1 ||
2959  ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
2960  {
2961  trunc->earliestExistingPage = segpage;
2962  }
2963 
2964  return false; /* keep going */
2965 }
const void * data
bool(* PagePrecedes)(int64, int64)
Definition: slru.h:160
int64 earliestExistingPage
Definition: multixact.c:2946

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

Referenced by TruncateMultiXact().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2089 of file multixact.c.

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

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

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

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

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

References Assert(), DEBUG1, DELAY_CHKPT_START, PGPROC::delayChkptFlags, mxtruncinfo::earliestExistingPage, elog, END_CRIT_SECTION, ereport, errmsg(), find_multixact_start(), MultiXactStateData::finishedStartup, FirstMultiXactId, LOG, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MULTIXACT_OFFSETS_PER_PAGE, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactIdPrecedesOrEquals(), MultiXactIdToOffsetSegment, MultiXactOffsetCtl, MultiXactState, MXOffsetToMemberSegment, MyProc, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, PerformMembersTruncation(), PerformOffsetsTruncation(), RecoveryInProgress(), SlruScanDirCbFindEarliest(), SlruScanDirectory(), START_CRIT_SECTION, and WriteMTruncateXlogRec().

Referenced by vac_truncate_clog().

◆ WriteMTruncateXlogRec()

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

Definition at line 3297 of file multixact.c.

3300 {
3301  XLogRecPtr recptr;
3302  xl_multixact_truncate xlrec;
3303 
3304  xlrec.oldestMultiDB = oldestMultiDB;
3305 
3306  xlrec.startTruncOff = startTruncOff;
3307  xlrec.endTruncOff = endTruncOff;
3308 
3309  xlrec.startTruncMemb = startTruncMemb;
3310  xlrec.endTruncMemb = endTruncMemb;
3311 
3312  XLogBeginInsert();
3313  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3314  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3315  XLogFlush(recptr);
3316 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2733
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 3283 of file multixact.c.

3284 {
3285  XLogBeginInsert();
3286  XLogRegisterData((char *) (&pageno), sizeof(pageno));
3287  (void) XLogInsert(RM_MULTIXACT_ID, info);
3288 }

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

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

◆ ZeroMultiXactMemberPage()

static int ZeroMultiXactMemberPage ( int64  pageno,
bool  writeXlog 
)
static

Definition at line 2026 of file multixact.c.

2027 {
2028  int slotno;
2029 
2030  slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
2031 
2032  if (writeXlog)
2034 
2035  return slotno;
2036 }
static void WriteMZeroPageXlogRec(int64 pageno, uint8 info)
Definition: multixact.c:3283
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
Definition: slru.c:361

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

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

◆ ZeroMultiXactOffsetPage()

static int ZeroMultiXactOffsetPage ( int64  pageno,
bool  writeXlog 
)
static

Definition at line 2010 of file multixact.c.

2011 {
2012  int slotno;
2013 
2014  slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
2015 
2016  if (writeXlog)
2018 
2019  return slotno;
2020 }

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

◆ MultiXactOffsetCtlData

SlruCtlData MultiXactOffsetCtlData
static

Definition at line 188 of file multixact.c.

◆ MultiXactState

◆ MXactCache

◆ MXactContext

MemoryContext MXactContext = NULL
static

Definition at line 325 of file multixact.c.

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

◆ OldestMemberMXactId

◆ OldestVisibleMXactId