PostgreSQL Source Code  git master
multixact.c File Reference
#include "postgres.h"
#include "access/multixact.h"
#include "access/slru.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "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/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 (int pageno, bool writeXlog)
 
static int ZeroMultiXactMemberPage (int pageno, bool writeXlog)
 
static bool MultiXactOffsetPagePrecedes (int page1, int page2)
 
static bool MultiXactMemberPagePrecedes (int page1, int 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 (int 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)
 
MultiXactId MultiXactIdCreateFromMembers (int nmembers, MultiXactMember *members)
 
int GetMultiXactIdMembers (MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
 
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)
 
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, int 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 dlist_head MXactCache = DLIST_STATIC_INIT(MXactCache)
 
static int MXactCacheMembers = 0
 
static MemoryContext MXactContext = NULL
 

Macro Definition Documentation

◆ debug_elog2

◆ debug_elog3

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

◆ debug_elog5

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

Definition at line 336 of file multixact.c.

Referenced by MultiXactIdExpand().

◆ debug_elog6

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

Definition at line 337 of file multixact.c.

Referenced by MultiXactGetCheckptMulti().

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

Definition at line 321 of file multixact.c.

Referenced by mXactCachePut().

◆ MAX_MEMBERS_IN_LAST_MEMBERS_PAGE

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

Definition at line 155 of file multixact.c.

Referenced by ExtendMultiXactMember().

◆ MaxOldestSlot

#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)

◆ MULTIXACT_FLAGBYTES_PER_GROUP

#define MULTIXACT_FLAGBYTES_PER_GROUP   4

Definition at line 135 of file multixact.c.

◆ MULTIXACT_MEMBER_DANGER_THRESHOLD

#define MULTIXACT_MEMBER_DANGER_THRESHOLD   (MaxMultiXactOffset - MaxMultiXactOffset / 4)

Definition at line 178 of file multixact.c.

Referenced by MultiXactMemberFreezeThreshold().

◆ MULTIXACT_MEMBER_SAFE_THRESHOLD

#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)

◆ MULTIXACT_MEMBERGROUP_SIZE

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

Definition at line 139 of file multixact.c.

◆ MULTIXACT_MEMBERGROUPS_PER_PAGE

#define MULTIXACT_MEMBERGROUPS_PER_PAGE   (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)

Definition at line 141 of file multixact.c.

◆ MULTIXACT_MEMBERS_PER_MEMBERGROUP

#define MULTIXACT_MEMBERS_PER_MEMBERGROUP   (MULTIXACT_FLAGBYTES_PER_GROUP * MXACT_MEMBER_FLAGS_PER_BYTE)

Definition at line 136 of file multixact.c.

◆ MULTIXACT_MEMBERS_PER_PAGE

◆ MULTIXACT_OFFSETS_PER_PAGE

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))

Definition at line 109 of file multixact.c.

Referenced by MultiXactOffsetPagePrecedes(), and TruncateMultiXact().

◆ MultiXactIdToOffsetEntry

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

◆ MultiXactIdToOffsetPage

◆ MultiXactIdToOffsetSegment

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

Definition at line 115 of file multixact.c.

Referenced by multixact_redo(), and TruncateMultiXact().

◆ MultiXactMemberCtl

◆ MultiXactOffsetCtl

◆ MXACT_MEMBER_BITS_PER_XACT

#define MXACT_MEMBER_BITS_PER_XACT   8

Definition at line 130 of file multixact.c.

Referenced by RecordNewMultiXact().

◆ MXACT_MEMBER_FLAGS_PER_BYTE

#define MXACT_MEMBER_FLAGS_PER_BYTE   1

Definition at line 131 of file multixact.c.

◆ MXACT_MEMBER_XACT_BITMASK

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

Definition at line 132 of file multixact.c.

Referenced by GetMultiXactIdMembers().

◆ MXOffsetToFlagsBitShift

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

Definition at line 167 of file multixact.c.

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

◆ MXOffsetToFlagsOffset

#define MXOffsetToFlagsOffset (   xid)
Value:
uint32 TransactionId
Definition: c.h:520
#define MULTIXACT_MEMBERGROUPS_PER_PAGE
Definition: multixact.c:141
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP
Definition: multixact.c:136
#define MULTIXACT_MEMBERGROUP_SIZE
Definition: multixact.c:139

Definition at line 163 of file multixact.c.

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

◆ MXOffsetToMemberOffset

#define MXOffsetToMemberOffset (   xid)
Value:
uint32 TransactionId
Definition: c.h:520
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP
Definition: multixact.c:136
#define MULTIXACT_FLAGBYTES_PER_GROUP
Definition: multixact.c:135

Definition at line 172 of file multixact.c.

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

◆ MXOffsetToMemberPage

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

◆ MXOffsetToMemberSegment

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

Definition at line 160 of file multixact.c.

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

◆ OFFSET_WARN_SEGMENTS

#define OFFSET_WARN_SEGMENTS   20

Referenced by GetNewMultiXactId().

◆ PreviousMultiXactId

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

Definition at line 181 of file multixact.c.

Referenced by PerformOffsetsTruncation().

◆ SHARED_MULTIXACT_STATE_SIZE

#define SHARED_MULTIXACT_STATE_SIZE
Value:
add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
Size mul_size(Size s1, Size s2)
Definition: shmem.c:515
Size add_size(Size s1, Size s2)
Definition: shmem.c:498
TransactionId MultiXactId
Definition: c.h:530
#define MaxOldestSlot
Definition: multixact.c:288
#define offsetof(type, field)
Definition: c.h:668

Referenced by MultiXactShmemInit(), and MultiXactShmemSize().

Typedef Documentation

◆ MultiXactStateData

◆ mXactCacheEnt

typedef struct mXactCacheEnt mXactCacheEnt

◆ mxtruncinfo

typedef struct mxtruncinfo mxtruncinfo

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1664 of file multixact.c.

References dlist_init(), InvalidMultiXactId, MXactCacheMembers, MyBackendId, OldestMemberMXactId, and OldestVisibleMXactId.

Referenced by AbortTransaction(), and CommitTransaction().

1665 {
1666  /*
1667  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1668  * which should only be valid while within a transaction.
1669  *
1670  * We assume that storing a MultiXactId is atomic and so we need not take
1671  * MultiXactGenLock to do this.
1672  */
1675 
1676  /*
1677  * Discard the local MultiXactId cache. Since MXactContext was created as
1678  * a child of TopTransactionContext, we needn't delete it explicitly.
1679  */
1680  MXactContext = NULL;
1682  MXactCacheMembers = 0;
1683 }
BackendId MyBackendId
Definition: globals.c:81
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
static int MXactCacheMembers
Definition: multixact.c:323
#define InvalidMultiXactId
Definition: multixact.h:24
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
static dlist_head MXactCache
Definition: multixact.c:322
static MemoryContext MXactContext
Definition: multixact.c:324

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1693 of file multixact.c.

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

Referenced by PrepareTransaction().

1694 {
1695  MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1696 
1697  if (MultiXactIdIsValid(myOldestMember))
1699  &myOldestMember, sizeof(MultiXactId));
1700 }
BackendId MyBackendId
Definition: globals.c:81
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1181
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27
TransactionId MultiXactId
Definition: c.h:530

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1870 of file multixact.c.

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

Referenced by BootStrapXLOG().

1871 {
1872  int slotno;
1873 
1874  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1875 
1876  /* Create and zero the first page of the offsets log */
1877  slotno = ZeroMultiXactOffsetPage(0, false);
1878 
1879  /* Make sure it's written out */
1881  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1882 
1883  LWLockRelease(MultiXactOffsetSLRULock);
1884 
1885  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
1886 
1887  /* Create and zero the first page of the members log */
1888  slotno = ZeroMultiXactMemberPage(0, false);
1889 
1890  /* Make sure it's written out */
1892  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1893 
1894  LWLockRelease(MultiXactMemberSLRULock);
1895 }
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1907
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:613
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:745
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1923
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2131 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

2132 {
2133  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2134 
2135  /*
2136  * Write dirty MultiXact pages to disk. This may result in sync requests
2137  * queued for later handling by ProcessSyncRequests(), as part of the
2138  * checkpoint.
2139  */
2142 
2143  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2144 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1155
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ ExtendMultiXactMember()

static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2410 of file multixact.c.

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

Referenced by GetNewMultiXactId().

2411 {
2412  /*
2413  * It's possible that the members span more than one page of the members
2414  * file, so we loop to ensure we consider each page. The coding is not
2415  * optimal if the members span several pages, but that seems unusual
2416  * enough to not worry much about.
2417  */
2418  while (nmembers > 0)
2419  {
2420  int flagsoff;
2421  int flagsbit;
2423 
2424  /*
2425  * Only zero when at first entry of a page.
2426  */
2427  flagsoff = MXOffsetToFlagsOffset(offset);
2428  flagsbit = MXOffsetToFlagsBitShift(offset);
2429  if (flagsoff == 0 && flagsbit == 0)
2430  {
2431  int pageno;
2432 
2433  pageno = MXOffsetToMemberPage(offset);
2434 
2435  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
2436 
2437  /* Zero the page and make an XLOG entry about it */
2438  ZeroMultiXactMemberPage(pageno, true);
2439 
2440  LWLockRelease(MultiXactMemberSLRULock);
2441  }
2442 
2443  /*
2444  * Compute the number of items till end of current page. Careful: if
2445  * addition of unsigned ints wraps around, we're at the last page of
2446  * the last segment; since that page holds a different number of items
2447  * than other pages, we need to do it differently.
2448  */
2449  if (offset + MAX_MEMBERS_IN_LAST_MEMBERS_PAGE < offset)
2450  {
2451  /*
2452  * This is the last page of the last segment; we can compute the
2453  * number of items left to allocate in it without modulo
2454  * arithmetic.
2455  */
2456  difference = MaxMultiXactOffset - offset + 1;
2457  }
2458  else
2460 
2461  /*
2462  * Advance to next page, taking care to properly handle the wraparound
2463  * case. OK if nmembers goes negative.
2464  */
2465  nmembers -= difference;
2466  offset += difference;
2467  }
2468 }
#define MaxMultiXactOffset
Definition: multixact.h:30
#define MXOffsetToFlagsBitShift(xid)
Definition: multixact.c:167
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:142
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
unsigned int uint32
Definition: c.h:374
Datum difference(PG_FUNCTION_ARGS)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1923
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE
Definition: multixact.c:155

◆ ExtendMultiXactOffset()

static void ExtendMultiXactOffset ( MultiXactId  multi)
static

Definition at line 2380 of file multixact.c.

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

Referenced by GetNewMultiXactId().

2381 {
2382  int pageno;
2383 
2384  /*
2385  * No work except at first MultiXactId of a page. But beware: just after
2386  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2387  */
2388  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2389  multi != FirstMultiXactId)
2390  return;
2391 
2392  pageno = MultiXactIdToOffsetPage(multi);
2393 
2394  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
2395 
2396  /* Zero the page and make an XLOG entry about it */
2397  ZeroMultiXactOffsetPage(pageno, true);
2398 
2399  LWLockRelease(MultiXactOffsetSLRULock);
2400 }
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1907
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
#define FirstMultiXactId
Definition: multixact.h:25
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208

◆ find_multixact_start()

static bool find_multixact_start ( MultiXactId  multi,
MultiXactOffset result 
)
static

Definition at line 2710 of file multixact.c.

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

Referenced by SetOffsetVacuumLimit(), and TruncateMultiXact().

2711 {
2712  MultiXactOffset offset;
2713  int pageno;
2714  int entryno;
2715  int slotno;
2716  MultiXactOffset *offptr;
2717 
2719 
2720  pageno = MultiXactIdToOffsetPage(multi);
2721  entryno = MultiXactIdToOffsetEntry(multi);
2722 
2723  /*
2724  * Write out dirty data, so PhysicalPageExists can work correctly.
2725  */
2728 
2730  return false;
2731 
2732  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2733  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2734  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2735  offptr += entryno;
2736  offset = *offptr;
2737  LWLockRelease(MultiXactOffsetSLRULock);
2738 
2739  *result = offset;
2740  return true;
2741 }
uint32 MultiXactOffset
Definition: c.h:532
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1155
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno)
Definition: slru.c:625
#define MultiXactOffsetCtl
Definition: multixact.c:190
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:494
#define Assert(condition)
Definition: c.h:745
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ GetMultiXactIdMembers()

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

Definition at line 1204 of file multixact.c.

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

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

1206 {
1207  int pageno;
1208  int prev_pageno;
1209  int entryno;
1210  int slotno;
1211  MultiXactOffset *offptr;
1212  MultiXactOffset offset;
1213  int length;
1214  int truelength;
1215  int i;
1216  MultiXactId oldestMXact;
1217  MultiXactId nextMXact;
1218  MultiXactId tmpMXact;
1219  MultiXactOffset nextOffset;
1220  MultiXactMember *ptr;
1221 
1222  debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
1223 
1224  if (!MultiXactIdIsValid(multi) || from_pgupgrade)
1225  return -1;
1226 
1227  /* See if the MultiXactId is in the local cache */
1228  length = mXactCacheGetById(multi, members);
1229  if (length >= 0)
1230  {
1231  debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
1232  mxid_to_string(multi, length, *members));
1233  return length;
1234  }
1235 
1236  /* Set our OldestVisibleMXactId[] entry if we didn't already */
1238 
1239  /*
1240  * If we know the multi is used only for locking and not for updates, then
1241  * we can skip checking if the value is older than our oldest visible
1242  * multi. It cannot possibly still be running.
1243  */
1244  if (onlyLock &&
1246  {
1247  debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
1248  *members = NULL;
1249  return -1;
1250  }
1251 
1252  /*
1253  * We check known limits on MultiXact before resorting to the SLRU area.
1254  *
1255  * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
1256  * useful; it has already been removed, or will be removed shortly, by
1257  * truncation. If one is passed, an error is raised.
1258  *
1259  * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
1260  * implies undetected ID wraparound has occurred. This raises a hard
1261  * error.
1262  *
1263  * Shared lock is enough here since we aren't modifying any global state.
1264  * Acquire it just long enough to grab the current counter values. We may
1265  * need both nextMXact and nextOffset; see below.
1266  */
1267  LWLockAcquire(MultiXactGenLock, LW_SHARED);
1268 
1269  oldestMXact = MultiXactState->oldestMultiXactId;
1270  nextMXact = MultiXactState->nextMXact;
1271  nextOffset = MultiXactState->nextOffset;
1272 
1273  LWLockRelease(MultiXactGenLock);
1274 
1275  if (MultiXactIdPrecedes(multi, oldestMXact))
1276  {
1277  ereport(ERROR,
1278  (errcode(ERRCODE_INTERNAL_ERROR),
1279  errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
1280  multi)));
1281  return -1;
1282  }
1283 
1284  if (!MultiXactIdPrecedes(multi, nextMXact))
1285  ereport(ERROR,
1286  (errcode(ERRCODE_INTERNAL_ERROR),
1287  errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
1288  multi)));
1289 
1290  /*
1291  * Find out the offset at which we need to start reading MultiXactMembers
1292  * and the number of members in the multixact. We determine the latter as
1293  * the difference between this multixact's starting offset and the next
1294  * one's. However, there are some corner cases to worry about:
1295  *
1296  * 1. This multixact may be the latest one created, in which case there is
1297  * no next one to look at. In this case the nextOffset value we just
1298  * saved is the correct endpoint.
1299  *
1300  * 2. The next multixact may still be in process of being filled in: that
1301  * is, another process may have done GetNewMultiXactId but not yet written
1302  * the offset entry for that ID. In that scenario, it is guaranteed that
1303  * the offset entry for that multixact exists (because GetNewMultiXactId
1304  * won't release MultiXactGenLock until it does) but contains zero
1305  * (because we are careful to pre-zero offset pages). Because
1306  * GetNewMultiXactId will never return zero as the starting offset for a
1307  * multixact, when we read zero as the next multixact's offset, we know we
1308  * have this case. We sleep for a bit and try again.
1309  *
1310  * 3. Because GetNewMultiXactId increments offset zero to offset one to
1311  * handle case #2, there is an ambiguity near the point of offset
1312  * wraparound. If we see next multixact's offset is one, is that our
1313  * multixact's actual endpoint, or did it end at zero with a subsequent
1314  * increment? We handle this using the knowledge that if the zero'th
1315  * member slot wasn't filled, it'll contain zero, and zero isn't a valid
1316  * transaction ID so it can't be a multixact member. Therefore, if we
1317  * read a zero from the members array, just ignore it.
1318  *
1319  * This is all pretty messy, but the mess occurs only in infrequent corner
1320  * cases, so it seems better than holding the MultiXactGenLock for a long
1321  * time on every multixact creation.
1322  */
1323 retry:
1324  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1325 
1326  pageno = MultiXactIdToOffsetPage(multi);
1327  entryno = MultiXactIdToOffsetEntry(multi);
1328 
1329  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
1330  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1331  offptr += entryno;
1332  offset = *offptr;
1333 
1334  Assert(offset != 0);
1335 
1336  /*
1337  * Use the same increment rule as GetNewMultiXactId(), that is, don't
1338  * handle wraparound explicitly until needed.
1339  */
1340  tmpMXact = multi + 1;
1341 
1342  if (nextMXact == tmpMXact)
1343  {
1344  /* Corner case 1: there is no next multixact */
1345  length = nextOffset - offset;
1346  }
1347  else
1348  {
1349  MultiXactOffset nextMXOffset;
1350 
1351  /* handle wraparound if needed */
1352  if (tmpMXact < FirstMultiXactId)
1353  tmpMXact = FirstMultiXactId;
1354 
1355  prev_pageno = pageno;
1356 
1357  pageno = MultiXactIdToOffsetPage(tmpMXact);
1358  entryno = MultiXactIdToOffsetEntry(tmpMXact);
1359 
1360  if (pageno != prev_pageno)
1361  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
1362 
1363  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1364  offptr += entryno;
1365  nextMXOffset = *offptr;
1366 
1367  if (nextMXOffset == 0)
1368  {
1369  /* Corner case 2: next multixact is still being filled in */
1370  LWLockRelease(MultiXactOffsetSLRULock);
1372  pg_usleep(1000L);
1373  goto retry;
1374  }
1375 
1376  length = nextMXOffset - offset;
1377  }
1378 
1379  LWLockRelease(MultiXactOffsetSLRULock);
1380 
1381  ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
1382  *members = ptr;
1383 
1384  /* Now get the members themselves. */
1385  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
1386 
1387  truelength = 0;
1388  prev_pageno = -1;
1389  for (i = 0; i < length; i++, offset++)
1390  {
1391  TransactionId *xactptr;
1392  uint32 *flagsptr;
1393  int flagsoff;
1394  int bshift;
1395  int memberoff;
1396 
1397  pageno = MXOffsetToMemberPage(offset);
1398  memberoff = MXOffsetToMemberOffset(offset);
1399 
1400  if (pageno != prev_pageno)
1401  {
1402  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
1403  prev_pageno = pageno;
1404  }
1405 
1406  xactptr = (TransactionId *)
1407  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1408 
1409  if (!TransactionIdIsValid(*xactptr))
1410  {
1411  /* Corner case 3: we must be looking at unused slot zero */
1412  Assert(offset == 0);
1413  continue;
1414  }
1415 
1416  flagsoff = MXOffsetToFlagsOffset(offset);
1417  bshift = MXOffsetToFlagsBitShift(offset);
1418  flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1419 
1420  ptr[truelength].xid = *xactptr;
1421  ptr[truelength].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
1422  truelength++;
1423  }
1424 
1425  LWLockRelease(MultiXactMemberSLRULock);
1426 
1427  /*
1428  * Copy the result into the local cache.
1429  */
1430  mXactCachePut(multi, truelength, ptr);
1431 
1432  debug_elog3(DEBUG2, "GetMembers: no cache for %s",
1433  mxid_to_string(multi, truelength, ptr));
1434  return truelength;
1435 }
MultiXactId nextMXact
Definition: multixact.c:203
BackendId MyBackendId
Definition: globals.c:81
#define MXOffsetToFlagsBitShift(xid)
Definition: multixact.c:167
uint32 MultiXactOffset
Definition: c.h:532
uint32 TransactionId
Definition: c.h:520
MultiXactOffset nextOffset
Definition: multixact.c:206
int errcode(int sqlerrcode)
Definition: elog.c:610
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
MultiXactId oldestMultiXactId
Definition: multixact.c:216
void pg_usleep(long microsec)
Definition: signal.c:53
#define ERROR
Definition: elog.h:43
TransactionId xid
Definition: multixact.h:62
#define MXOffsetToMemberOffset(xid)
Definition: multixact.c:172
#define MXACT_MEMBER_XACT_BITMASK
Definition: multixact.c:132
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:394
#define DEBUG2
Definition: elog.h:24
MultiXactStatus status
Definition: multixact.h:63
unsigned int uint32
Definition: c.h:374
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define debug_elog2(a, b)
Definition: multixact.c:333
#define FirstMultiXactId
Definition: multixact.h:25
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1633
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define debug_elog3(a, b, c)
Definition: multixact.c:334
#define ereport(elevel,...)
Definition: elog.h:144
TransactionId MultiXactId
Definition: c.h:530
#define Assert(condition)
Definition: c.h:745
static void MultiXactIdSetOldestVisible(void)
Definition: multixact.c:682
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1563
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3127
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:824
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
Definition: multixact.c:1517
int i
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ GetNewMultiXactId()

static MultiXactId GetNewMultiXactId ( int  nmembers,
MultiXactOffset offset 
)
static

Definition at line 937 of file multixact.c.

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

938 {
939  MultiXactId result;
940  MultiXactOffset nextOffset;
941 
942  debug_elog3(DEBUG2, "GetNew: for %d xids", nmembers);
943 
944  /* safety check, we should never get this far in a HS standby */
945  if (RecoveryInProgress())
946  elog(ERROR, "cannot assign MultiXactIds during recovery");
947 
948  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
949 
950  /* Handle wraparound of the nextMXact counter */
953 
954  /* Assign the MXID */
955  result = MultiXactState->nextMXact;
956 
957  /*----------
958  * Check to see if it's safe to assign another MultiXactId. This protects
959  * against catastrophic data loss due to multixact wraparound. The basic
960  * rules are:
961  *
962  * If we're past multiVacLimit or the safe threshold for member storage
963  * space, or we don't know what the safe threshold for member storage is,
964  * start trying to force autovacuum cycles.
965  * If we're past multiWarnLimit, start issuing warnings.
966  * If we're past multiStopLimit, refuse to create new MultiXactIds.
967  *
968  * Note these are pretty much the same protections in GetNewTransactionId.
969  *----------
970  */
972  {
973  /*
974  * For safety's sake, we release MultiXactGenLock while sending
975  * signals, warnings, etc. This is not so much because we care about
976  * preserving concurrency in this situation, as to avoid any
977  * possibility of deadlock while doing get_database_name(). First,
978  * copy all the shared values we'll need in this path.
979  */
980  MultiXactId multiWarnLimit = MultiXactState->multiWarnLimit;
981  MultiXactId multiStopLimit = MultiXactState->multiStopLimit;
982  MultiXactId multiWrapLimit = MultiXactState->multiWrapLimit;
983  Oid oldest_datoid = MultiXactState->oldestMultiXactDB;
984 
985  LWLockRelease(MultiXactGenLock);
986 
987  if (IsUnderPostmaster &&
988  !MultiXactIdPrecedes(result, multiStopLimit))
989  {
990  char *oldest_datname = get_database_name(oldest_datoid);
991 
992  /*
993  * Immediately kick autovacuum into action as we're already in
994  * ERROR territory.
995  */
997 
998  /* complain even if that DB has disappeared */
999  if (oldest_datname)
1000  ereport(ERROR,
1001  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1002  errmsg("database is not accepting commands that generate new MultiXactIds to avoid wraparound data loss in database \"%s\"",
1003  oldest_datname),
1004  errhint("Execute a database-wide VACUUM in that database.\n"
1005  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1006  else
1007  ereport(ERROR,
1008  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1009  errmsg("database is not accepting commands that generate new MultiXactIds to avoid wraparound data loss in database with OID %u",
1010  oldest_datoid),
1011  errhint("Execute a database-wide VACUUM in that database.\n"
1012  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1013  }
1014 
1015  /*
1016  * To avoid swamping the postmaster with signals, we issue the autovac
1017  * request only once per 64K multis generated. This still gives
1018  * plenty of chances before we get into real trouble.
1019  */
1020  if (IsUnderPostmaster && (result % 65536) == 0)
1022 
1023  if (!MultiXactIdPrecedes(result, multiWarnLimit))
1024  {
1025  char *oldest_datname = get_database_name(oldest_datoid);
1026 
1027  /* complain even if that DB has disappeared */
1028  if (oldest_datname)
1029  ereport(WARNING,
1030  (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
1031  "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
1032  multiWrapLimit - result,
1033  oldest_datname,
1034  multiWrapLimit - result),
1035  errhint("Execute a database-wide VACUUM in that database.\n"
1036  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1037  else
1038  ereport(WARNING,
1039  (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
1040  "database with OID %u must be vacuumed before %u more MultiXactIds are used",
1041  multiWrapLimit - result,
1042  oldest_datoid,
1043  multiWrapLimit - result),
1044  errhint("Execute a database-wide VACUUM in that database.\n"
1045  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1046  }
1047 
1048  /* Re-acquire lock and start over */
1049  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1050  result = MultiXactState->nextMXact;
1051  if (result < FirstMultiXactId)
1052  result = FirstMultiXactId;
1053  }
1054 
1055  /* Make sure there is room for the MXID in the file. */
1056  ExtendMultiXactOffset(result);
1057 
1058  /*
1059  * Reserve the members space, similarly to above. Also, be careful not to
1060  * return zero as the starting offset for any multixact. See
1061  * GetMultiXactIdMembers() for motivation.
1062  */
1063  nextOffset = MultiXactState->nextOffset;
1064  if (nextOffset == 0)
1065  {
1066  *offset = 1;
1067  nmembers++; /* allocate member slot 0 too */
1068  }
1069  else
1070  *offset = nextOffset;
1071 
1072  /*----------
1073  * Protect against overrun of the members space as well, with the
1074  * following rules:
1075  *
1076  * If we're past offsetStopLimit, refuse to generate more multis.
1077  * If we're close to offsetStopLimit, emit a warning.
1078  *
1079  * Arbitrarily, we start emitting warnings when we're 20 segments or less
1080  * from offsetStopLimit.
1081  *
1082  * Note we haven't updated the shared state yet, so if we fail at this
1083  * point, the multixact ID we grabbed can still be used by the next guy.
1084  *
1085  * Note that there is no point in forcing autovacuum runs here: the
1086  * multixact freeze settings would have to be reduced for that to have any
1087  * effect.
1088  *----------
1089  */
1090 #define OFFSET_WARN_SEGMENTS 20
1093  nmembers))
1094  {
1095  /* see comment in the corresponding offsets wraparound case */
1097 
1098  ereport(ERROR,
1099  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1100  errmsg("multixact \"members\" limit exceeded"),
1101  errdetail_plural("This command would create a multixact with %u members, but the remaining space is only enough for %u member.",
1102  "This command would create a multixact with %u members, but the remaining space is only enough for %u members.",
1103  MultiXactState->offsetStopLimit - nextOffset - 1,
1104  nmembers,
1105  MultiXactState->offsetStopLimit - nextOffset - 1),
1106  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.",
1108  }
1109 
1110  /*
1111  * Check whether we should kick autovacuum into action, to prevent members
1112  * wraparound. NB we use a much larger window to trigger autovacuum than
1113  * just the warning limit. The warning is just a measure of last resort -
1114  * this is in line with GetNewTransactionId's behaviour.
1115  */
1119  {
1120  /*
1121  * To avoid swamping the postmaster with signals, we issue the autovac
1122  * request only when crossing a segment boundary. With default
1123  * compilation settings that's roughly after 50k members. This still
1124  * gives plenty of chances before we get into real trouble.
1125  */
1126  if ((MXOffsetToMemberPage(nextOffset) / SLRU_PAGES_PER_SEGMENT) !=
1127  (MXOffsetToMemberPage(nextOffset + nmembers) / SLRU_PAGES_PER_SEGMENT))
1129  }
1130 
1133  nextOffset,
1135  ereport(WARNING,
1136  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1137  errmsg_plural("database with OID %u must be vacuumed before %d more multixact member is used",
1138  "database with OID %u must be vacuumed before %d more multixact members are used",
1139  MultiXactState->offsetStopLimit - nextOffset + nmembers,
1141  MultiXactState->offsetStopLimit - nextOffset + nmembers),
1142  errhint("Execute a database-wide VACUUM in that database with reduced vacuum_multixact_freeze_min_age and vacuum_multixact_freeze_table_age settings.")));
1143 
1144  ExtendMultiXactMember(nextOffset, nmembers);
1145 
1146  /*
1147  * Critical section from here until caller has written the data into the
1148  * just-reserved SLRU space; we don't want to error out with a partly
1149  * written MultiXact structure. (In particular, failing to write our
1150  * start offset after advancing nextMXact would effectively corrupt the
1151  * previous MultiXact.)
1152  */
1154 
1155  /*
1156  * Advance counters. As in GetNewTransactionId(), this must not happen
1157  * until after file extension has succeeded!
1158  *
1159  * We don't care about MultiXactId wraparound here; it will be handled by
1160  * the next iteration. But note that nextMXact may be InvalidMultiXactId
1161  * or the first value on a segment-beginning page after this routine
1162  * exits, so anyone else looking at the variable must be prepared to deal
1163  * with either case. Similarly, nextOffset may be zero, but we won't use
1164  * that as the actual start offset of the next multixact.
1165  */
1167 
1168  MultiXactState->nextOffset += nmembers;
1169 
1170  LWLockRelease(MultiXactGenLock);
1171 
1172  debug_elog4(DEBUG2, "GetNew: returning %u offset %u", result, *offset);
1173  return result;
1174 }
MultiXactId nextMXact
Definition: multixact.c:203
int errhint(const char *fmt,...)
Definition: elog.c:1071
uint32 MultiXactOffset
Definition: c.h:532
#define debug_elog4(a, b, c, d)
Definition: multixact.c:335
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:934
MultiXactOffset nextOffset
Definition: multixact.c:206
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:142
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
int errcode(int sqlerrcode)
Definition: elog.c:610
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
unsigned int Oid
Definition: postgres_ext.h:31
bool RecoveryInProgress(void)
Definition: xlog.c:8074
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
static bool MultiXactOffsetWouldWrap(MultiXactOffset boundary, MultiXactOffset start, uint32 distance)
Definition: multixact.c:2662
#define ERROR
Definition: elog.h:43
MultiXactId multiVacLimit
Definition: multixact.c:228
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2155
#define DEBUG2
Definition: elog.h:24
bool IsUnderPostmaster
Definition: globals.c:109
MultiXactId multiStopLimit
Definition: multixact.c:230
#define FirstMultiXactId
Definition: multixact.h:25
#define WARNING
Definition: elog.h:40
MultiXactOffset offsetStopLimit
Definition: multixact.c:234
MultiXactOffset oldestOffset
Definition: multixact.c:224
#define debug_elog3(a, b, c)
Definition: multixact.c:334
#define OFFSET_WARN_SEGMENTS
static void ExtendMultiXactOffset(MultiXactId multi)
Definition: multixact.c:2380
#define ereport(elevel,...)
Definition: elog.h:144
TransactionId MultiXactId
Definition: c.h:530
MultiXactId multiWrapLimit
Definition: multixact.c:231
int errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1049
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3127
MultiXactId multiWarnLimit
Definition: multixact.c:229
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
void SendPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:146
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:177
static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
Definition: multixact.c:2410

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2482 of file multixact.c.

References FirstMultiXactId, i, LW_SHARED, LWLockAcquire(), LWLockRelease(), MaxOldestSlot, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactStateData::nextMXact, OldestMemberMXactId, and OldestVisibleMXactId.

Referenced by heapam_relation_set_new_filenode(), vac_update_datfrozenxid(), and vacuum_set_xid_limits().

2483 {
2484  MultiXactId oldestMXact;
2485  MultiXactId nextMXact;
2486  int i;
2487 
2488  /*
2489  * This is the oldest valid value among all the OldestMemberMXactId[] and
2490  * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2491  */
2492  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2493 
2494  /*
2495  * We have to beware of the possibility that nextMXact is in the
2496  * wrapped-around state. We don't fix the counter itself here, but we
2497  * must be sure to use a valid value in our calculation.
2498  */
2499  nextMXact = MultiXactState->nextMXact;
2500  if (nextMXact < FirstMultiXactId)
2501  nextMXact = FirstMultiXactId;
2502 
2503  oldestMXact = nextMXact;
2504  for (i = 1; i <= MaxOldestSlot; i++)
2505  {
2506  MultiXactId thisoldest;
2507 
2508  thisoldest = OldestMemberMXactId[i];
2509  if (MultiXactIdIsValid(thisoldest) &&
2510  MultiXactIdPrecedes(thisoldest, oldestMXact))
2511  oldestMXact = thisoldest;
2512  thisoldest = OldestVisibleMXactId[i];
2513  if (MultiXactIdIsValid(thisoldest) &&
2514  MultiXactIdPrecedes(thisoldest, oldestMXact))
2515  oldestMXact = thisoldest;
2516  }
2517 
2518  LWLockRelease(MultiXactGenLock);
2519 
2520  return oldestMXact;
2521 }
MultiXactId nextMXact
Definition: multixact.c:203
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define FirstMultiXactId
Definition: multixact.h:25
TransactionId MultiXactId
Definition: c.h:530
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3127
int i
#define MaxOldestSlot
Definition: multixact.c:288

◆ MaybeExtendOffsetSlru()

static void MaybeExtendOffsetSlru ( void  )
static

Definition at line 1951 of file multixact.c.

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

Referenced by MultiXactSetNextMXact().

1952 {
1953  int pageno;
1954 
1956 
1957  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1958 
1960  {
1961  int slotno;
1962 
1963  /*
1964  * Fortunately for us, SimpleLruWritePage is already prepared to deal
1965  * with creating a new segment file even if the page we're writing is
1966  * not the first in it, so this is enough.
1967  */
1968  slotno = ZeroMultiXactOffsetPage(pageno, false);
1970  }
1971 
1972  LWLockRelease(MultiXactOffsetSLRULock);
1973 }
MultiXactId nextMXact
Definition: multixact.c:203
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1907
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno)
Definition: slru.c:625
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:613
#define MultiXactOffsetCtl
Definition: multixact.c:190
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 3204 of file multixact.c.

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(), RecordNewMultiXact(), SetMultiXactIdLimit(), 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().

3205 {
3206  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3207 
3208  /* Backup blocks are not used in multixact records */
3209  Assert(!XLogRecHasAnyBlockRefs(record));
3210 
3211  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3212  {
3213  int pageno;
3214  int slotno;
3215 
3216  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3217 
3218  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
3219 
3220  slotno = ZeroMultiXactOffsetPage(pageno, false);
3222  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3223 
3224  LWLockRelease(MultiXactOffsetSLRULock);
3225  }
3226  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3227  {
3228  int pageno;
3229  int slotno;
3230 
3231  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3232 
3233  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
3234 
3235  slotno = ZeroMultiXactMemberPage(pageno, false);
3237  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3238 
3239  LWLockRelease(MultiXactMemberSLRULock);
3240  }
3241  else if (info == XLOG_MULTIXACT_CREATE_ID)
3242  {
3243  xl_multixact_create *xlrec =
3244  (xl_multixact_create *) XLogRecGetData(record);
3245  TransactionId max_xid;
3246  int i;
3247 
3248  /* Store the data back into the SLRU files */
3249  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3250  xlrec->members);
3251 
3252  /* Make sure nextMXact/nextOffset are beyond what this record has */
3253  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3254  xlrec->moff + xlrec->nmembers);
3255 
3256  /*
3257  * Make sure nextXid is beyond any XID mentioned in the record.
3258  * This should be unnecessary, since any XID found here ought to have
3259  * other evidence in the XLOG, but let's be safe.
3260  */
3261  max_xid = XLogRecGetXid(record);
3262  for (i = 0; i < xlrec->nmembers; i++)
3263  {
3264  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3265  max_xid = xlrec->members[i].xid;
3266  }
3267 
3269  }
3270  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3271  {
3272  xl_multixact_truncate xlrec;
3273  int pageno;
3274 
3275  memcpy(&xlrec, XLogRecGetData(record),
3277 
3278  elog(DEBUG1, "replaying multixact truncation: "
3279  "offsets [%u, %u), offsets segments [%x, %x), "
3280  "members [%u, %u), members segments [%x, %x)",
3281  xlrec.startTruncOff, xlrec.endTruncOff,
3284  xlrec.startTruncMemb, xlrec.endTruncMemb,
3287 
3288  /* should not be required, but more than cheap enough */
3289  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3290 
3291  /*
3292  * Advance the horizon values, so they're current at the end of
3293  * recovery.
3294  */
3295  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3296 
3298 
3299  /*
3300  * During XLOG replay, latest_page_number isn't necessarily set up
3301  * yet; insert a suitable value to bypass the sanity test in
3302  * SimpleLruTruncate.
3303  */
3304  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3305  MultiXactOffsetCtl->shared->latest_page_number = pageno;
3307 
3308  LWLockRelease(MultiXactTruncationLock);
3309  }
3310  else
3311  elog(PANIC, "multixact_redo: unknown op code %u", info);
3312 }
#define DEBUG1
Definition: elog.h:25
uint32 TransactionId
Definition: c.h:520
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:277
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1907
unsigned char uint8
Definition: c.h:372
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:73
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2338
#define PANIC
Definition: elog.h:53
#define SizeOfMultiXactTruncate
Definition: multixact.h:100
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:82
#define XLogRecGetData(decoder)
Definition: xlogreader.h:310
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:74
TransactionId xid
Definition: multixact.h:62
MultiXactOffset moff
Definition: multixact.h:80
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2867
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:613
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:305
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
MultiXactOffset endTruncMemb
Definition: multixact.h:97
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:307
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:72
MultiXactOffset startTruncMemb
Definition: multixact.h:96
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2189
MultiXactId mid
Definition: multixact.h:79
#define Assert(condition)
Definition: c.h:745
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:75
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
MultiXactId startTruncOff
Definition: multixact.h:92
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1923
#define elog(elevel,...)
Definition: elog.h:214
int i
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:312
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:843
MultiXactId endTruncOff
Definition: multixact.h:93
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2895
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ multixact_twophase_postabort()

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

Definition at line 1793 of file multixact.c.

References multixact_twophase_postcommit().

1795 {
1796  multixact_twophase_postcommit(xid, info, recdata, len);
1797 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1778

◆ multixact_twophase_postcommit()

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

Definition at line 1778 of file multixact.c.

References Assert, InvalidMultiXactId, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

Referenced by multixact_twophase_postabort().

1780 {
1781  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, true);
1782 
1783  Assert(len == sizeof(MultiXactId));
1784 
1785  OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
1786 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:858
int BackendId
Definition: backendid.h:21
#define InvalidMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:530
#define Assert(condition)
Definition: c.h:745

◆ multixact_twophase_recover()

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

Definition at line 1757 of file multixact.c.

References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

1759 {
1760  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1761  MultiXactId oldestMember;
1762 
1763  /*
1764  * Get the oldest member XID from the state file record, and set it in the
1765  * OldestMemberMXactId slot reserved for this prepared transaction.
1766  */
1767  Assert(len == sizeof(MultiXactId));
1768  oldestMember = *((MultiXactId *) recdata);
1769 
1770  OldestMemberMXactId[dummyBackendId] = oldestMember;
1771 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:858
int BackendId
Definition: backendid.h:21
TransactionId MultiXactId
Definition: c.h:530
#define Assert(condition)
Definition: c.h:745

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2338 of file multixact.c.

References DEBUG2, debug_elog3, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdPrecedes(), MultiXactOffsetPrecedes(), MultiXactStateData::nextMXact, and MultiXactStateData::nextOffset.

Referenced by multixact_redo(), and xlog_redo().

2340 {
2341  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2343  {
2344  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2345  MultiXactState->nextMXact = minMulti;
2346  }
2347  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2348  {
2349  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2350  minMultiOffset);
2351  MultiXactState->nextOffset = minMultiOffset;
2352  }
2353  LWLockRelease(MultiXactGenLock);
2354 }
MultiXactId nextMXact
Definition: multixact.c:203
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
#define DEBUG2
Definition: elog.h:24
#define debug_elog3(a, b, c)
Definition: multixact.c:334
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3127
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3153

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2363 of file multixact.c.

References Assert, InRecovery, MultiXactIdPrecedes(), MultiXactStateData::oldestMultiXactId, and SetMultiXactIdLimit().

Referenced by xlog_redo().

2364 {
2365  Assert(InRecovery);
2366 
2368  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2369 }
bool InRecovery
Definition: xlog.c:205
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
MultiXactId oldestMultiXactId
Definition: multixact.c:216
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2189
#define Assert(condition)
Definition: c.h:745
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3127

◆ MultiXactGetCheckptMulti()

void MultiXactGetCheckptMulti ( bool  is_shutdown,
MultiXactId nextMulti,
MultiXactOffset nextMultiOffset,
MultiXactId oldestMulti,
Oid oldestMultiDB 
)

Definition at line 2109 of file multixact.c.

References DEBUG2, debug_elog6, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, and MultiXactStateData::oldestMultiXactId.

Referenced by CreateCheckPoint().

2114 {
2115  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2116  *nextMulti = MultiXactState->nextMXact;
2117  *nextMultiOffset = MultiXactState->nextOffset;
2118  *oldestMulti = MultiXactState->oldestMultiXactId;
2119  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2120  LWLockRelease(MultiXactGenLock);
2121 
2123  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2124  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2125 }
MultiXactId nextMXact
Definition: multixact.c:203
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:337
#define DEBUG2
Definition: elog.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208

◆ MultiXactIdCreate()

MultiXactId MultiXactIdCreate ( TransactionId  xid1,
MultiXactStatus  status1,
TransactionId  xid2,
MultiXactStatus  status2 
)

Definition at line 386 of file multixact.c.

References Assert, AssertArg, DEBUG2, debug_elog3, MultiXactIdCreateFromMembers(), MultiXactIdIsValid, mxid_to_string(), MyBackendId, OldestMemberMXactId, MultiXactMember::status, TransactionIdEquals, TransactionIdIsValid, and MultiXactMember::xid.

Referenced by compute_new_xmax_infomask().

388 {
389  MultiXactId newMulti;
390  MultiXactMember members[2];
391 
394 
395  Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2));
396 
397  /* MultiXactIdSetOldestMember() must have been called already. */
399 
400  /*
401  * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
402  * are still running. In typical usage, xid2 will be our own XID and the
403  * caller just did a check on xid1, so it'd be wasted effort.
404  */
405 
406  members[0].xid = xid1;
407  members[0].status = status1;
408  members[1].xid = xid2;
409  members[1].status = status2;
410 
411  newMulti = MultiXactIdCreateFromMembers(2, members);
412 
413  debug_elog3(DEBUG2, "Create: %s",
414  mxid_to_string(newMulti, 2, members));
415 
416  return newMulti;
417 }
BackendId MyBackendId
Definition: globals.c:81
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:748
TransactionId xid
Definition: multixact.h:62
#define DEBUG2
Definition: elog.h:24
MultiXactStatus status
Definition: multixact.h:63
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1633
#define AssertArg(condition)
Definition: c.h:747
#define debug_elog3(a, b, c)
Definition: multixact.c:334
TransactionId MultiXactId
Definition: c.h:530
#define Assert(condition)
Definition: c.h:745
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 748 of file multixact.c.

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, status(), XLOG_MULTIXACT_CREATE_ID, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by FreezeMultiXactId(), MultiXactIdCreate(), and MultiXactIdExpand().

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

◆ MultiXactIdExpand()

MultiXactId MultiXactIdExpand ( MultiXactId  multi,
TransactionId  xid,
MultiXactStatus  status 
)

Definition at line 439 of file multixact.c.

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

Referenced by compute_new_xmax_infomask().

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

◆ MultiXactIdIsRunning()

bool MultiXactIdIsRunning ( MultiXactId  multi,
bool  isLockOnly 
)

Definition at line 551 of file multixact.c.

References DEBUG2, debug_elog2, debug_elog3, debug_elog4, GetMultiXactIdMembers(), i, pfree(), TransactionIdIsCurrentTransactionId(), and TransactionIdIsInProgress().

Referenced by compute_new_xmax_infomask(), FreezeMultiXactId(), HeapTupleSatisfiesUpdate(), and HeapTupleSatisfiesVacuumHorizon().

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

◆ MultiXactIdPrecedes()

◆ MultiXactIdPrecedesOrEquals()

bool MultiXactIdPrecedesOrEquals ( MultiXactId  multi1,
MultiXactId  multi2 
)

Definition at line 3141 of file multixact.c.

Referenced by heap_vacuum_rel(), and TruncateMultiXact().

3142 {
3143  int32 diff = (int32) (multi1 - multi2);
3144 
3145  return (diff <= 0);
3146 }
signed int int32
Definition: c.h:362

◆ MultiXactIdSetOldestMember()

void MultiXactIdSetOldestMember ( void  )

Definition at line 625 of file multixact.c.

References DEBUG2, debug_elog4, FirstMultiXactId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MyBackendId, MultiXactStateData::nextMXact, and OldestMemberMXactId.

Referenced by heap_delete(), heap_lock_tuple(), heap_lock_updated_tuple(), and heap_update().

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

◆ MultiXactIdSetOldestVisible()

static void MultiXactIdSetOldestVisible ( void  )
static

Definition at line 682 of file multixact.c.

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

Referenced by GetMultiXactIdMembers().

683 {
685  {
686  MultiXactId oldestMXact;
687  int i;
688 
689  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
690 
691  /*
692  * We have to beware of the possibility that nextMXact is in the
693  * wrapped-around state. We don't fix the counter itself here, but we
694  * must be sure to store a valid value in our array entry.
695  */
696  oldestMXact = MultiXactState->nextMXact;
697  if (oldestMXact < FirstMultiXactId)
698  oldestMXact = FirstMultiXactId;
699 
700  for (i = 1; i <= MaxOldestSlot; i++)
701  {
702  MultiXactId thisoldest = OldestMemberMXactId[i];
703 
704  if (MultiXactIdIsValid(thisoldest) &&
705  MultiXactIdPrecedes(thisoldest, oldestMXact))
706  oldestMXact = thisoldest;
707  }
708 
709  OldestVisibleMXactId[MyBackendId] = oldestMXact;
710 
711  LWLockRelease(MultiXactGenLock);
712 
713  debug_elog4(DEBUG2, "MultiXact: setting OldestVisible[%d] = %u",
714  MyBackendId, oldestMXact);
715  }
716 }
MultiXactId nextMXact
Definition: multixact.c:203
BackendId MyBackendId
Definition: globals.c:81
#define debug_elog4(a, b, c, d)
Definition: multixact.c:335
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
#define DEBUG2
Definition: elog.h:24
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define FirstMultiXactId
Definition: multixact.h:25
TransactionId MultiXactId
Definition: c.h:530
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3127
int i
#define MaxOldestSlot
Definition: multixact.c:288

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2804 of file multixact.c.

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

2805 {
2806  MultiXactOffset members;
2807  uint32 multixacts;
2808  uint32 victim_multixacts;
2809  double fraction;
2810 
2811  /* If we can't determine member space utilization, assume the worst. */
2812  if (!ReadMultiXactCounts(&multixacts, &members))
2813  return 0;
2814 
2815  /* If member space utilization is low, no special action is required. */
2816  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2818 
2819  /*
2820  * Compute a target for relminmxid advancement. The number of multixacts
2821  * we try to eliminate from the system is based on how far we are past
2822  * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2823  */
2824  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2826  victim_multixacts = multixacts * fraction;
2827 
2828  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2829  if (victim_multixacts > multixacts)
2830  return 0;
2831  return multixacts - victim_multixacts;
2832 }
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:178
uint32 MultiXactOffset
Definition: c.h:532
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:125
unsigned int uint32
Definition: c.h:374
static bool ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
Definition: multixact.c:2748
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:177

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 3109 of file multixact.c.

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

3110 {
3111  MultiXactOffset offset1;
3112  MultiXactOffset offset2;
3113 
3114  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3115  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3116 
3117  return MultiXactOffsetPrecedes(offset1, offset2);
3118 }
uint32 MultiXactOffset
Definition: c.h:532
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:142
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3153

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3392 of file multixact.c.

References MultiXactMemberCtl, and SlruSyncFileTag().

3393 {
3394  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3395 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1489
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 3091 of file multixact.c.

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

3092 {
3093  MultiXactId multi1;
3094  MultiXactId multi2;
3095 
3096  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3097  multi1 += FirstMultiXactId;
3098  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3099  multi2 += FirstMultiXactId;
3100 
3101  return MultiXactIdPrecedes(multi1, multi2);
3102 }
#define FirstMultiXactId
Definition: multixact.h:25
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
TransactionId MultiXactId
Definition: c.h:530
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3127

◆ MultiXactOffsetPrecedes()

static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3153 of file multixact.c.

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

3154 {
3155  int32 diff = (int32) (offset1 - offset2);
3156 
3157  return (diff < 0);
3158 }
signed int int32
Definition: c.h:362

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3383 of file multixact.c.

References MultiXactOffsetCtl, and SlruSyncFileTag().

3384 {
3385  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3386 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1489
#define MultiXactOffsetCtl
Definition: multixact.c:190

◆ MultiXactOffsetWouldWrap()

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

Definition at line 2662 of file multixact.c.

Referenced by GetNewMultiXactId().

2664 {
2665  MultiXactOffset finish;
2666 
2667  /*
2668  * Note that offset number 0 is not used (see GetMultiXactIdMembers), so
2669  * if the addition wraps around the UINT_MAX boundary, skip that value.
2670  */
2671  finish = start + distance;
2672  if (finish < start)
2673  finish++;
2674 
2675  /*-----------------------------------------------------------------------
2676  * When the boundary is numerically greater than the starting point, any
2677  * value numerically between the two is not wrapped:
2678  *
2679  * <----S----B---->
2680  * [---) = F wrapped past B (and UINT_MAX)
2681  * [---) = F not wrapped
2682  * [----] = F wrapped past B
2683  *
2684  * When the boundary is numerically less than the starting point (i.e. the
2685  * UINT_MAX wraparound occurs somewhere in between) then all values in
2686  * between are wrapped:
2687  *
2688  * <----B----S---->
2689  * [---) = F not wrapped past B (but wrapped past UINT_MAX)
2690  * [---) = F wrapped past B (and UINT_MAX)
2691  * [----] = F not wrapped
2692  *-----------------------------------------------------------------------
2693  */
2694  if (start < boundary)
2695  return finish >= boundary || finish < start;
2696  else
2697  return finish >= boundary && finish < start;
2698 }
uint32 MultiXactOffset
Definition: c.h:532

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2155 of file multixact.c.

References DEBUG2, debug_elog4, IsBinaryUpgrade, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaybeExtendOffsetSlru(), MultiXactStateData::nextMXact, and MultiXactStateData::nextOffset.

Referenced by BootStrapXLOG(), StartupXLOG(), and xlog_redo().

2157 {
2158  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2159  nextMulti, nextMultiOffset);
2160  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2161  MultiXactState->nextMXact = nextMulti;
2162  MultiXactState->nextOffset = nextMultiOffset;
2163  LWLockRelease(MultiXactGenLock);
2164 
2165  /*
2166  * During a binary upgrade, make sure that the offsets SLRU is large
2167  * enough to contain the next value that would be created.
2168  *
2169  * We need to do this pretty early during the first startup in binary
2170  * upgrade mode: before StartupMultiXact() in fact, because this routine
2171  * is called even before that by StartupXLOG(). And we can't do it
2172  * earlier than at this point, because during that first call of this
2173  * routine we determine the MultiXactState->nextMXact value that
2174  * MaybeExtendOffsetSlru needs.
2175  */
2176  if (IsBinaryUpgrade)
2178 }
MultiXactId nextMXact
Definition: multixact.c:203
#define debug_elog4(a, b, c, d)
Definition: multixact.c:335
MultiXactOffset nextOffset
Definition: multixact.c:206
static void MaybeExtendOffsetSlru(void)
Definition: multixact.c:1951
bool IsBinaryUpgrade
Definition: globals.c:110
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
#define DEBUG2
Definition: elog.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208

◆ MultiXactShmemInit()

void MultiXactShmemInit ( void  )

Definition at line 1822 of file multixact.c.

References Assert, DEBUG2, debug_elog2, IsUnderPostmaster, LWTRANCHE_MULTIXACTMEMBER_BUFFER, LWTRANCHE_MULTIXACTOFFSET_BUFFER, MaxOldestSlot, MemSet, MultiXactMemberCtl, MultiXactMemberPagePrecedes(), MultiXactOffsetCtl, MultiXactOffsetPagePrecedes(), NUM_MULTIXACTMEMBER_BUFFERS, NUM_MULTIXACTOFFSET_BUFFERS, OldestMemberMXactId, OldestVisibleMXactId, MultiXactStateData::perBackendXactIds, SHARED_MULTIXACT_STATE_SIZE, ShmemInitStruct(), SimpleLruInit(), SYNC_HANDLER_MULTIXACT_MEMBER, and SYNC_HANDLER_MULTIXACT_OFFSET.

Referenced by CreateSharedMemoryAndSemaphores().

1823 {
1824  bool found;
1825 
1826  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1827 
1830 
1832  "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
1833  MultiXactOffsetSLRULock, "pg_multixact/offsets",
1837  "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
1838  MultiXactMemberSLRULock, "pg_multixact/members",
1841 
1842  /* Initialize our shared state struct */
1843  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1845  &found);
1846  if (!IsUnderPostmaster)
1847  {
1848  Assert(!found);
1849 
1850  /* Make sure we zero out the per-backend state */
1852  }
1853  else
1854  Assert(found);
1855 
1856  /*
1857  * Set up array pointers. Note that perBackendXactIds[0] is wasted space
1858  * since we only use indexes 1..MaxOldestSlot in each array.
1859  */
1862 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:281
static bool MultiXactOffsetPagePrecedes(int page1, int page2)
Definition: multixact.c:3091
#define MemSet(start, val, len)
Definition: c.h:949
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
#define NUM_MULTIXACTOFFSET_BUFFERS
Definition: multixact.h:33
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id, SyncRequestHandler sync_handler)
Definition: slru.c:186
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:392
#define DEBUG2
Definition: elog.h:24
bool IsUnderPostmaster
Definition: globals.c:109
#define debug_elog2(a, b)
Definition: multixact.c:333
static bool MultiXactMemberPagePrecedes(int page1, int page2)
Definition: multixact.c:3109
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:745
#define MaxOldestSlot
Definition: multixact.c:288
#define MultiXactMemberCtl
Definition: multixact.c:191
#define SHARED_MULTIXACT_STATE_SIZE
#define NUM_MULTIXACTMEMBER_BUFFERS
Definition: multixact.h:34

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1805 of file multixact.c.

References add_size(), NUM_MULTIXACTMEMBER_BUFFERS, NUM_MULTIXACTOFFSET_BUFFERS, SHARED_MULTIXACT_STATE_SIZE, and SimpleLruShmemSize().

Referenced by CreateSharedMemoryAndSemaphores().

1806 {
1807  Size size;
1808 
1809  /* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
1810 #define SHARED_MULTIXACT_STATE_SIZE \
1811  add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
1812  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1813 
1817 
1818  return size;
1819 }
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:155
#define NUM_MULTIXACTOFFSET_BUFFERS
Definition: multixact.h:33
Size add_size(Size s1, Size s2)
Definition: shmem.c:498
size_t Size
Definition: c.h:473
#define SHARED_MULTIXACT_STATE_SIZE
#define NUM_MULTIXACTMEMBER_BUFFERS
Definition: multixact.h:34

◆ mXactCacheGetById()

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

Definition at line 1517 of file multixact.c.

References dlist_iter::cur, DEBUG2, debug_elog2, debug_elog3, dlist_container, dlist_foreach, dlist_move_head(), mXactCacheEnt::members, mXactCacheEnt::multi, mxid_to_string(), mXactCacheEnt::nmembers, and palloc().

Referenced by GetMultiXactIdMembers().

1518 {
1519  dlist_iter iter;
1520 
1521  debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1522 
1523  dlist_foreach(iter, &MXactCache)
1524  {
1525  mXactCacheEnt *entry = dlist_container(mXactCacheEnt, node, iter.cur);
1526 
1527  if (entry->multi == multi)
1528  {
1529  MultiXactMember *ptr;
1530  Size size;
1531 
1532  size = sizeof(MultiXactMember) * entry->nmembers;
1533  ptr = (MultiXactMember *) palloc(size);
1534  *members = ptr;
1535 
1536  memcpy(ptr, entry->members, size);
1537 
1538  debug_elog3(DEBUG2, "CacheGet: found %s",
1539  mxid_to_string(multi,
1540  entry->nmembers,
1541  entry->members));
1542 
1543  /*
1544  * Note we modify the list while not using a modifiable iterator.
1545  * This is acceptable only because we exit the iteration
1546  * immediately afterwards.
1547  */
1548  dlist_move_head(&MXactCache, iter.cur);
1549 
1550  return entry->nmembers;
1551  }
1552  }
1553 
1554  debug_elog2(DEBUG2, "CacheGet: not found");
1555  return -1;
1556 }
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:318
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
#define DEBUG2
Definition: elog.h:24
#define debug_elog2(a, b)
Definition: multixact.c:333
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1633
#define debug_elog3(a, b, c)
Definition: multixact.c:334
dlist_node * cur
Definition: ilist.h:161
static dlist_head MXactCache
Definition: multixact.c:322
struct MultiXactMember MultiXactMember
size_t Size
Definition: c.h:473
static void dlist_move_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:385
void * palloc(Size size)
Definition: mcxt.c:950
MultiXactId multi
Definition: multixact.c:315

◆ mXactCacheGetBySet()

static MultiXactId mXactCacheGetBySet ( int  nmembers,
MultiXactMember members 
)
static

Definition at line 1475 of file multixact.c.

References dlist_iter::cur, DEBUG2, debug_elog2, debug_elog3, dlist_container, dlist_foreach, dlist_move_head(), InvalidMultiXactId, mXactCacheEnt::members, mXactCacheEnt::multi, mxactMemberComparator(), mxid_to_string(), mXactCacheEnt::nmembers, and qsort.

Referenced by MultiXactIdCreateFromMembers().

1476 {
1477  dlist_iter iter;
1478 
1479  debug_elog3(DEBUG2, "CacheGet: looking for %s",
1480  mxid_to_string(InvalidMultiXactId, nmembers, members));
1481 
1482  /* sort the array so comparison is easy */
1483  qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1484 
1485  dlist_foreach(iter, &MXactCache)
1486  {
1487  mXactCacheEnt *entry = dlist_container(mXactCacheEnt, node, iter.cur);
1488 
1489  if (entry->nmembers != nmembers)
1490  continue;
1491 
1492  /*
1493  * We assume the cache entries are sorted, and that the unused bits in
1494  * "status" are zeroed.
1495  */
1496  if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1497  {
1498  debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1499  dlist_move_head(&MXactCache, iter.cur);
1500  return entry->multi;
1501  }
1502  }
1503 
1504  debug_elog2(DEBUG2, "CacheGet: not found :-(");
1505  return InvalidMultiXactId;
1506 }
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:318
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
#define DEBUG2
Definition: elog.h:24
#define debug_elog2(a, b)
Definition: multixact.c:333
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1633
#define debug_elog3(a, b, c)
Definition: multixact.c:334
#define InvalidMultiXactId
Definition: multixact.h:24
dlist_node * cur
Definition: ilist.h:161
static dlist_head MXactCache
Definition: multixact.c:322
static void dlist_move_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:385
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition: multixact.c:1445
#define qsort(a, b, c, d)
Definition: port.h:475
MultiXactId multi
Definition: multixact.c:315

◆ mXactCachePut()

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

Definition at line 1563 of file multixact.c.

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, DEBUG2, debug_elog2, debug_elog3, dlist_container, dlist_delete(), dlist_push_head(), dlist_tail_node(), MAX_CACHE_ENTRIES, mXactCacheEnt::members, MemoryContextAlloc(), mXactCacheEnt::multi, MXactCacheMembers, mxactMemberComparator(), mxid_to_string(), mXactCacheEnt::nmembers, mXactCacheEnt::node, offsetof, pfree(), qsort, and TopTransactionContext.

Referenced by GetMultiXactIdMembers(), and MultiXactIdCreateFromMembers().

1564 {
1565  mXactCacheEnt *entry;
1566 
1567  debug_elog3(DEBUG2, "CachePut: storing %s",
1568  mxid_to_string(multi, nmembers, members));
1569 
1570  if (MXactContext == NULL)
1571  {
1572  /* The cache only lives as long as the current transaction */
1573  debug_elog2(DEBUG2, "CachePut: initializing memory context");
1575  "MultiXact cache context",
1577  }
1578 
1579  entry = (mXactCacheEnt *)
1581  offsetof(mXactCacheEnt, members) +
1582  nmembers * sizeof(MultiXactMember));
1583 
1584  entry->multi = multi;
1585  entry->nmembers = nmembers;
1586  memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1587 
1588  /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1589  qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1590 
1591  dlist_push_head(&MXactCache, &entry->node);
1593  {
1594  dlist_node *node;
1595  mXactCacheEnt *entry;
1596 
1597  node = dlist_tail_node(&MXactCache);
1598  dlist_delete(node);
1600 
1601  entry = dlist_container(mXactCacheEnt, node, node);
1602  debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1603  entry->multi);
1604 
1605  pfree(entry);
1606  }
1607 }
#define AllocSetContextCreate
Definition: memutils.h:170
MemoryContext TopTransactionContext
Definition: mcxt.c:49
static void dlist_push_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:300
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:318
static dlist_node * dlist_tail_node(dlist_head *head)
Definition: ilist.h:466
#define MAX_CACHE_ENTRIES
Definition: multixact.c:321
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
dlist_node node
Definition: multixact.c:317
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
void pfree(void *pointer)
Definition: mcxt.c:1057
static int MXactCacheMembers
Definition: multixact.c:323
#define DEBUG2
Definition: elog.h:24
#define debug_elog2(a, b)
Definition: multixact.c:333
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1633
#define debug_elog3(a, b, c)
Definition: multixact.c:334
static dlist_head MXactCache
Definition: multixact.c:322
struct MultiXactMember MultiXactMember
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition: multixact.c:1445
static MemoryContext MXactContext
Definition: multixact.c:324
#define qsort(a, b, c, d)
Definition: port.h:475
MultiXactId multi
Definition: multixact.c:315
#define offsetof(type, field)
Definition: c.h:668

◆ mxactMemberComparator()

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

Definition at line 1445 of file multixact.c.

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

Referenced by mXactCacheGetBySet(), and mXactCachePut().

1446 {
1447  MultiXactMember member1 = *(const MultiXactMember *) arg1;
1448  MultiXactMember member2 = *(const MultiXactMember *) arg2;
1449 
1450  if (member1.xid > member2.xid)
1451  return 1;
1452  if (member1.xid < member2.xid)
1453  return -1;
1454  if (member1.status > member2.status)
1455  return 1;
1456  if (member1.status < member2.status)
1457  return -1;
1458  return 0;
1459 }
TransactionId xid
Definition: multixact.h:62
MultiXactStatus status
Definition: multixact.h:63

◆ mxid_to_string()

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

Definition at line 1633 of file multixact.c.

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

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

1634 {
1635  static char *str = NULL;
1637  int i;
1638 
1639  if (str != NULL)
1640  pfree(str);
1641 
1642  initStringInfo(&buf);
1643 
1644  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1645  mxstatus_to_string(members[0].status));
1646 
1647  for (i = 1; i < nmembers; i++)
1648  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1649  mxstatus_to_string(members[i].status));
1650 
1651  appendStringInfoChar(&buf, ']');
1653  pfree(buf.data);
1654  return str;
1655 }
void pfree(void *pointer)
Definition: mcxt.c:1057
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
static char * buf
Definition: pg_test_fsync.c:67
MemoryContext TopMemoryContext
Definition: mcxt.c:44
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1174
int i
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1610
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ mxstatus_to_string()

static char * mxstatus_to_string ( MultiXactStatus  status)
static

Definition at line 1610 of file multixact.c.

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

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

1611 {
1612  switch (status)
1613  {
1615  return "keysh";
1617  return "sh";
1619  return "fornokeyupd";
1621  return "forupd";
1623  return "nokeyupd";
1624  case MultiXactStatusUpdate:
1625  return "upd";
1626  default:
1627  elog(ERROR, "unrecognized multixact status %d", status);
1628  return "";
1629  }
1630 }
#define ERROR
Definition: elog.h:43
#define elog(elevel,...)
Definition: elog.h:214
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ PerformMembersTruncation()

static void PerformMembersTruncation ( MultiXactOffset  oldestOffset,
MultiXactOffset  newOldestOffset 
)
static

Definition at line 2867 of file multixact.c.

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

Referenced by multixact_redo(), and TruncateMultiXact().

2868 {
2869  const int maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
2870  int startsegment = MXOffsetToMemberSegment(oldestOffset);
2871  int endsegment = MXOffsetToMemberSegment(newOldestOffset);
2872  int segment = startsegment;
2873 
2874  /*
2875  * Delete all the segments but the last one. The last segment can still
2876  * contain, possibly partially, valid data.
2877  */
2878  while (segment != endsegment)
2879  {
2880  elog(DEBUG2, "truncating multixact members segment %x", segment);
2882 
2883  /* move to next segment, handling wraparound correctly */
2884  if (segment == maxsegment)
2885  segment = 0;
2886  else
2887  segment += 1;
2888  }
2889 }
#define MaxMultiXactOffset
Definition: multixact.h:30
#define DEBUG2
Definition: elog.h:24
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
#define elog(elevel,...)
Definition: elog.h:214
void SlruDeleteSegment(SlruCtl ctl, int segno)
Definition: slru.c:1321
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ PerformOffsetsTruncation()

static void PerformOffsetsTruncation ( MultiXactId  oldestMulti,
MultiXactId  newOldestMulti 
)
static

Definition at line 2895 of file multixact.c.

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

Referenced by multixact_redo(), and TruncateMultiXact().

2896 {
2897  /*
2898  * We step back one multixact to avoid passing a cutoff page that hasn't
2899  * been created yet in the rare case that oldestMulti would be the first
2900  * item on a page and oldestMulti == nextMulti. In that case, if we
2901  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
2902  * detection.
2903  */
2905  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
2906 }
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1225
#define PreviousMultiXactId(xid)
Definition: multixact.c:181
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
#define MultiXactOffsetCtl
Definition: multixact.c:190

◆ pg_get_multixact_members()

Datum pg_get_multixact_members ( PG_FUNCTION_ARGS  )

Definition at line 3315 of file multixact.c.

References FuncCallContext::attinmeta, BuildTupleFromCStrings(), CreateTemplateTupleDesc(), ereport, errcode(), errmsg(), ERROR, FirstMultiXactId, GetMultiXactIdMembers(), HeapTupleGetDatum, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, mxstatus_to_string(), palloc(), pfree(), PG_GETARG_UINT32, psprintf(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, TupleDescGetAttInMetadata(), TupleDescInitEntry(), FuncCallContext::user_fctx, and values.

3316 {
3317  typedef struct
3318  {
3319  MultiXactMember *members;
3320  int nmembers;
3321  int iter;
3322  } mxact;
3323  MultiXactId mxid = PG_GETARG_UINT32(0);
3324  mxact *multi;
3325  FuncCallContext *funccxt;
3326 
3327  if (mxid < FirstMultiXactId)
3328  ereport(ERROR,
3329  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3330  errmsg("invalid MultiXactId: %u", mxid)));
3331 
3332  if (SRF_IS_FIRSTCALL())
3333  {
3334  MemoryContext oldcxt;
3335  TupleDesc tupdesc;
3336 
3337  funccxt = SRF_FIRSTCALL_INIT();
3338  oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3339 
3340  multi = palloc(sizeof(mxact));
3341  /* no need to allow for old values here */
3342  multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3343  false);
3344  multi->iter = 0;
3345 
3346  tupdesc = CreateTemplateTupleDesc(2);
3347  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid",
3348  XIDOID, -1, 0);
3349  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "mode",
3350  TEXTOID, -1, 0);
3351 
3352  funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3353  funccxt->user_fctx = multi;
3354 
3355  MemoryContextSwitchTo(oldcxt);
3356  }
3357 
3358  funccxt = SRF_PERCALL_SETUP();
3359  multi = (mxact *) funccxt->user_fctx;
3360 
3361  while (multi->iter < multi->nmembers)
3362  {
3363  HeapTuple tuple;
3364  char *values[2];
3365 
3366  values[0] = psprintf("%u", multi->members[multi->iter].xid);
3367  values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3368 
3369  tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3370 
3371  multi->iter++;
3372  pfree(values[0]);
3373  SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3374  }
3375 
3376  SRF_RETURN_DONE(funccxt);
3377 }
#define PG_GETARG_UINT32(n)
Definition: fmgr.h:270
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:293
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:297
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2116
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:299
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ERROR
Definition: elog.h:43
AttInMetadata * attinmeta
Definition: funcapi.h:91
#define FirstMultiXactId
Definition: multixact.h:25
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2067
#define ereport(elevel,...)
Definition: elog.h:144
TransactionId MultiXactId
Definition: c.h:530
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
static Datum values[MAXATTR]
Definition: bootstrap.c:165
void * user_fctx
Definition: funcapi.h:82
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:824
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1610
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1204
int16 AttrNumber
Definition: attnum.h:21
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:317
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:295

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1707 of file multixact.c.

References dlist_init(), InvalidMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MXactCacheMembers, MyBackendId, OldestMemberMXactId, OldestVisibleMXactId, and TwoPhaseGetDummyBackendId().

Referenced by PrepareTransaction().

1708 {
1709  MultiXactId myOldestMember;
1710 
1711  /*
1712  * Transfer our OldestMemberMXactId value to the slot reserved for the
1713  * prepared transaction.
1714  */
1715  myOldestMember = OldestMemberMXactId[MyBackendId];
1716  if (MultiXactIdIsValid(myOldestMember))
1717  {
1718  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1719 
1720  /*
1721  * Even though storing MultiXactId is atomic, acquire lock to make
1722  * sure others see both changes, not just the reset of the slot of the
1723  * current backend. Using a volatile pointer might suffice, but this
1724  * isn't a hot spot.
1725  */
1726  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1727 
1728  OldestMemberMXactId[dummyBackendId] = myOldestMember;
1730 
1731  LWLockRelease(MultiXactGenLock);
1732  }
1733 
1734  /*
1735  * We don't need to transfer OldestVisibleMXactId value, because the
1736  * transaction is not going to be looking at any more multixacts once it's
1737  * prepared.
1738  *
1739  * We assume that storing a MultiXactId is atomic and so we need not take
1740  * MultiXactGenLock to do this.
1741  */
1743 
1744  /*
1745  * Discard the local MultiXactId cache like in AtEOX_MultiXact
1746  */
1747  MXactContext = NULL;
1749  MXactCacheMembers = 0;
1750 }
BackendId MyBackendId
Definition: globals.c:81
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
static int MXactCacheMembers
Definition: multixact.c:323
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:858
int BackendId
Definition: backendid.h:21
#define InvalidMultiXactId
Definition: multixact.h:24
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
TransactionId MultiXactId
Definition: c.h:530
static dlist_head MXactCache
Definition: multixact.c:322
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
static MemoryContext MXactContext
Definition: multixact.c:324

◆ ReadMultiXactCounts()

static bool ReadMultiXactCounts ( uint32 multixacts,
MultiXactOffset members 
)
static

Definition at line 2748 of file multixact.c.

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

Referenced by MultiXactMemberFreezeThreshold().

2749 {
2750  MultiXactOffset nextOffset;
2751  MultiXactOffset oldestOffset;
2752  MultiXactId oldestMultiXactId;
2753  MultiXactId nextMultiXactId;
2754  bool oldestOffsetKnown;
2755 
2756  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2757  nextOffset = MultiXactState->nextOffset;
2758  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2759  nextMultiXactId = MultiXactState->nextMXact;
2760  oldestOffset = MultiXactState->oldestOffset;
2761  oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2762  LWLockRelease(MultiXactGenLock);
2763 
2764  if (!oldestOffsetKnown)
2765  return false;
2766 
2767  *members = nextOffset - oldestOffset;
2768  *multixacts = nextMultiXactId - oldestMultiXactId;
2769  return true;
2770 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:532
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
MultiXactId oldestMultiXactId
Definition: multixact.c:216
MultiXactOffset oldestOffset
Definition: multixact.c:224
TransactionId MultiXactId
Definition: c.h:530
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208

◆ ReadNextMultiXactId()

MultiXactId ReadNextMultiXactId ( void  )

Definition at line 723 of file multixact.c.

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

Referenced by ATRewriteTables(), AutoVacWorkerMain(), do_start_worker(), mxid_age(), refresh_by_heap_swap(), vac_update_datfrozenxid(), vac_update_relstats(), and vacuum_set_xid_limits().

724 {
725  MultiXactId mxid;
726 
727  /* XXX we could presumably do this without a lock. */
728  LWLockAcquire(MultiXactGenLock, LW_SHARED);
729  mxid = MultiXactState->nextMXact;
730  LWLockRelease(MultiXactGenLock);
731 
732  if (mxid < FirstMultiXactId)
733  mxid = FirstMultiXactId;
734 
735  return mxid;
736 }
MultiXactId nextMXact
Definition: multixact.c:203
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
#define FirstMultiXactId
Definition: multixact.h:25
TransactionId MultiXactId
Definition: c.h:530
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208

◆ RecordNewMultiXact()

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

Definition at line 843 of file multixact.c.

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

Referenced by multixact_redo(), and MultiXactIdCreateFromMembers().

845 {
846  int pageno;
847  int prev_pageno;
848  int entryno;
849  int slotno;
850  MultiXactOffset *offptr;
851  int i;
852 
853  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
854 
855  pageno = MultiXactIdToOffsetPage(multi);
856  entryno = MultiXactIdToOffsetEntry(multi);
857 
858  /*
859  * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
860  * to complain about if there's any I/O error. This is kinda bogus, but
861  * since the errors will always give the full pathname, it should be clear
862  * enough that a MultiXactId is really involved. Perhaps someday we'll
863  * take the trouble to generalize the slru.c error reporting code.
864  */
865  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
866  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
867  offptr += entryno;
868 
869  *offptr = offset;
870 
871  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
872 
873  /* Exchange our lock */
874  LWLockRelease(MultiXactOffsetSLRULock);
875 
876  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
877 
878  prev_pageno = -1;
879 
880  for (i = 0; i < nmembers; i++, offset++)
881  {
882  TransactionId *memberptr;
883  uint32 *flagsptr;
884  uint32 flagsval;
885  int bshift;
886  int flagsoff;
887  int memberoff;
888 
889  Assert(members[i].status <= MultiXactStatusUpdate);
890 
891  pageno = MXOffsetToMemberPage(offset);
892  memberoff = MXOffsetToMemberOffset(offset);
893  flagsoff = MXOffsetToFlagsOffset(offset);
894  bshift = MXOffsetToFlagsBitShift(offset);
895 
896  if (pageno != prev_pageno)
897  {
898  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
899  prev_pageno = pageno;
900  }
901 
902  memberptr = (TransactionId *)
903  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
904 
905  *memberptr = members[i].xid;
906 
907  flagsptr = (uint32 *)
908  (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
909 
910  flagsval = *flagsptr;
911  flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
912  flagsval |= (members[i].status << bshift);
913  *flagsptr = flagsval;
914 
915  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
916  }
917 
918  LWLockRelease(MultiXactMemberSLRULock);
919 }
#define MXOffsetToFlagsBitShift(xid)
Definition: multixact.c:167
uint32 MultiXactOffset
Definition: c.h:532
uint32 TransactionId
Definition: c.h:520
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
TransactionId xid
Definition: multixact.h:62
#define MXOffsetToMemberOffset(xid)
Definition: multixact.c:172
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:394
MultiXactStatus status
Definition: multixact.h:63
unsigned int uint32
Definition: c.h:374
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:745
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
#define MXACT_MEMBER_BITS_PER_XACT
Definition: multixact.c:130
int i
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ SetMultiXactIdLimit()

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

Definition at line 2189 of file multixact.c.

References Assert, autovacuum_multixact_freeze_max_age, DEBUG1, ereport, errhint(), errmsg(), 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(), 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().

2191 {
2192  MultiXactId multiVacLimit;
2193  MultiXactId multiWarnLimit;
2194  MultiXactId multiStopLimit;
2195  MultiXactId multiWrapLimit;
2196  MultiXactId curMulti;
2197  bool needs_offset_vacuum;
2198 
2199  Assert(MultiXactIdIsValid(oldest_datminmxid));
2200 
2201  /*
2202  * We pretend that a wrap will happen halfway through the multixact ID
2203  * space, but that's not really true, because multixacts wrap differently
2204  * from transaction IDs. Note that, separately from any concern about
2205  * multixact IDs wrapping, we must ensure that multixact members do not
2206  * wrap. Limits for that are set in SetOffsetVacuumLimit, not here.
2207  */
2208  multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
2209  if (multiWrapLimit < FirstMultiXactId)
2210  multiWrapLimit += FirstMultiXactId;
2211 
2212  /*
2213  * We'll refuse to continue assigning MultiXactIds once we get within 3M
2214  * multi of data loss. See SetTransactionIdLimit.
2215  */
2216  multiStopLimit = multiWrapLimit - 3000000;
2217  if (multiStopLimit < FirstMultiXactId)
2218  multiStopLimit -= FirstMultiXactId;
2219 
2220  /*
2221  * We'll start complaining loudly when we get within 40M multis of data
2222  * loss. This is kind of arbitrary, but if you let your gas gauge get
2223  * down to 2% of full, would you be looking for the next gas station? We
2224  * need to be fairly liberal about this number because there are lots of
2225  * scenarios where most transactions are done by automatic clients that
2226  * won't pay attention to warnings. (No, we're not gonna make this
2227  * configurable. If you know enough to configure it, you know enough to
2228  * not get in this kind of trouble in the first place.)
2229  */
2230  multiWarnLimit = multiWrapLimit - 40000000;
2231  if (multiWarnLimit < FirstMultiXactId)
2232  multiWarnLimit -= FirstMultiXactId;
2233 
2234  /*
2235  * We'll start trying to force autovacuums when oldest_datminmxid gets to
2236  * be more than autovacuum_multixact_freeze_max_age mxids old.
2237  *
2238  * Note: autovacuum_multixact_freeze_max_age is a PGC_POSTMASTER parameter
2239  * so that we don't have to worry about dealing with on-the-fly changes in
2240  * its value. See SetTransactionIdLimit.
2241  */
2242  multiVacLimit = oldest_datminmxid + autovacuum_multixact_freeze_max_age;
2243  if (multiVacLimit < FirstMultiXactId)
2244  multiVacLimit += FirstMultiXactId;
2245 
2246  /* Grab lock for just long enough to set the new limit values */
2247  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2248  MultiXactState->oldestMultiXactId = oldest_datminmxid;
2249  MultiXactState->oldestMultiXactDB = oldest_datoid;
2250  MultiXactState->multiVacLimit = multiVacLimit;
2251  MultiXactState->multiWarnLimit = multiWarnLimit;
2252  MultiXactState->multiStopLimit = multiStopLimit;
2253  MultiXactState->multiWrapLimit = multiWrapLimit;
2254  curMulti = MultiXactState->nextMXact;
2255  LWLockRelease(MultiXactGenLock);
2256 
2257  /* Log the info */
2258  ereport(DEBUG1,
2259  (errmsg("MultiXactId wrap limit is %u, limited by database with OID %u",
2260  multiWrapLimit, oldest_datoid)));
2261 
2262  /*
2263  * Computing the actual limits is only possible once the data directory is
2264  * in a consistent state. There's no need to compute the limits while
2265  * still replaying WAL - no decisions about new multis are made even
2266  * though multixact creations might be replayed. So we'll only do further
2267  * checks after TrimMultiXact() has been called.
2268  */
2270  return;
2271 
2272  Assert(!InRecovery);
2273 
2274  /* Set limits for offset vacuum. */
2275  needs_offset_vacuum = SetOffsetVacuumLimit(is_startup);
2276 
2277  /*
2278  * If past the autovacuum force point, immediately signal an autovac
2279  * request. The reason for this is that autovac only processes one
2280  * database per invocation. Once it's finished cleaning up the oldest
2281  * database, it'll call here, and we'll signal the postmaster to start
2282  * another iteration immediately if there are still any old databases.
2283  */
2284  if ((MultiXactIdPrecedes(multiVacLimit, curMulti) ||
2285  needs_offset_vacuum) && IsUnderPostmaster)
2287 
2288  /* Give an immediate warning if past the wrap warn point */
2289  if (MultiXactIdPrecedes(multiWarnLimit, curMulti))
2290  {
2291  char *oldest_datname;
2292 
2293  /*
2294  * We can be called when not inside a transaction, for example during
2295  * StartupXLOG(). In such a case we cannot do database access, so we
2296  * must just report the oldest DB's OID.
2297  *
2298  * Note: it's also possible that get_database_name fails and returns
2299  * NULL, for example because the database just got dropped. We'll
2300  * still warn, even though the warning might now be unnecessary.
2301  */
2302  if (IsTransactionState())
2303  oldest_datname = get_database_name(oldest_datoid);
2304  else
2305  oldest_datname = NULL;
2306 
2307  if (oldest_datname)
2308  ereport(WARNING,
2309  (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
2310  "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
2311  multiWrapLimit - curMulti,
2312  oldest_datname,
2313  multiWrapLimit - curMulti),
2314  errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
2315  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2316  else
2317  ereport(WARNING,
2318  (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
2319  "database with OID %u must be vacuumed before %u more MultiXactIds are used",
2320  multiWrapLimit - curMulti,
2321  oldest_datoid,
2322  multiWrapLimit - curMulti),
2323  errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
2324  "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2325  }
2326 }
MultiXactId nextMXact
Definition: multixact.c:203
#define DEBUG1
Definition: elog.h:25
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define MaxMultiXactId
Definition: multixact.h:26
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:934
bool InRecovery
Definition: xlog.c:205
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:125
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
MultiXactId oldestMultiXactId
Definition: multixact.c:216
static bool SetOffsetVacuumLimit(bool is_startup)
Definition: multixact.c:2535
MultiXactId multiVacLimit
Definition: multixact.c:228
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2155
bool IsUnderPostmaster
Definition: globals.c:109
MultiXactId multiStopLimit
Definition: multixact.c:230
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define FirstMultiXactId
Definition: multixact.h:25
#define WARNING
Definition: elog.h:40
#define ereport(elevel,...)
Definition: elog.h:144
TransactionId MultiXactId
Definition: c.h:530
MultiXactId multiWrapLimit
Definition: multixact.c:231
#define Assert(condition)
Definition: c.h:745
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
bool IsTransactionState(void)
Definition: xact.c:371
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3127
MultiXactId multiWarnLimit
Definition: multixact.c:229
int errmsg(const char *fmt,...)
Definition: elog.c:824
void SendPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:146

◆ SetOffsetVacuumLimit()

static bool SetOffsetVacuumLimit ( bool  is_startup)
static

Definition at line 2535 of file multixact.c.

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

Referenced by SetMultiXactIdLimit().

2536 {
2537  MultiXactId oldestMultiXactId;
2538  MultiXactId nextMXact;
2539  MultiXactOffset oldestOffset = 0; /* placate compiler */
2540  MultiXactOffset prevOldestOffset;
2541  MultiXactOffset nextOffset;
2542  bool oldestOffsetKnown = false;
2543  bool prevOldestOffsetKnown;
2544  MultiXactOffset offsetStopLimit = 0;
2545  MultiXactOffset prevOffsetStopLimit;
2546 
2547  /*
2548  * NB: Have to prevent concurrent truncation, we might otherwise try to
2549  * lookup an oldestMulti that's concurrently getting truncated away.
2550  */
2551  LWLockAcquire(MultiXactTruncationLock, LW_SHARED);
2552 
2553  /* Read relevant fields from shared memory. */
2554  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2555  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2556  nextMXact = MultiXactState->nextMXact;
2557  nextOffset = MultiXactState->nextOffset;
2558  prevOldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2559  prevOldestOffset = MultiXactState->oldestOffset;
2560  prevOffsetStopLimit = MultiXactState->offsetStopLimit;
2562  LWLockRelease(MultiXactGenLock);
2563 
2564  /*
2565  * Determine the offset of the oldest multixact. Normally, we can read
2566  * the offset from the multixact itself, but there's an important special
2567  * case: if there are no multixacts in existence at all, oldestMXact
2568  * obviously can't point to one. It will instead point to the multixact
2569  * ID that will be assigned the next time one is needed.
2570  */
2571  if (oldestMultiXactId == nextMXact)
2572  {
2573  /*
2574  * When the next multixact gets created, it will be stored at the next
2575  * offset.
2576  */
2577  oldestOffset = nextOffset;
2578  oldestOffsetKnown = true;
2579  }
2580  else
2581  {
2582  /*
2583  * Figure out where the oldest existing multixact's offsets are
2584  * stored. Due to bugs in early release of PostgreSQL 9.3.X and 9.4.X,
2585  * the supposedly-earliest multixact might not really exist. We are
2586  * careful not to fail in that case.
2587  */
2588  oldestOffsetKnown =
2589  find_multixact_start(oldestMultiXactId, &oldestOffset);
2590 
2591  if (oldestOffsetKnown)
2592  ereport(DEBUG1,
2593  (errmsg("oldest MultiXactId member is at offset %u",
2594  oldestOffset)));
2595  else
2596  ereport(LOG,
2597  (errmsg("MultiXact member wraparound protections are disabled because oldest checkpointed MultiXact %u does not exist on disk",
2598  oldestMultiXactId)));
2599  }
2600 
2601  LWLockRelease(MultiXactTruncationLock);
2602 
2603  /*
2604  * If we can, compute limits (and install them MultiXactState) to prevent
2605  * overrun of old data in the members SLRU area. We can only do so if the
2606  * oldest offset is known though.
2607  */
2608  if (oldestOffsetKnown)
2609  {
2610  /* move back to start of the corresponding segment */
2611  offsetStopLimit = oldestOffset - (oldestOffset %
2613 
2614  /* always leave one segment before the wraparound point */
2615  offsetStopLimit -= (MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT);
2616 
2617  if (!prevOldestOffsetKnown && !is_startup)
2618  ereport(LOG,
2619  (errmsg("MultiXact member wraparound protections are now enabled")));
2620 
2621  ereport(DEBUG1,
2622  (errmsg("MultiXact member stop limit is now %u based on MultiXact %u",
2623  offsetStopLimit, oldestMultiXactId)));
2624  }
2625  else if (prevOldestOffsetKnown)
2626  {
2627  /*
2628  * If we failed to get the oldest offset this time, but we have a
2629  * value from a previous pass through this function, use the old
2630  * values rather than automatically forcing an emergency autovacuum
2631  * cycle again.
2632  */
2633  oldestOffset = prevOldestOffset;
2634  oldestOffsetKnown = true;
2635  offsetStopLimit = prevOffsetStopLimit;
2636  }
2637 
2638  /* Install the computed values */
2639  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2640  MultiXactState->oldestOffset = oldestOffset;
2641  MultiXactState->oldestOffsetKnown = oldestOffsetKnown;
2642  MultiXactState->offsetStopLimit = offsetStopLimit;
2643  LWLockRelease(MultiXactGenLock);
2644 
2645  /*
2646  * Do we need an emergency autovacuum? If we're not sure, assume yes.
2647  */
2648  return !oldestOffsetKnown ||
2649  (nextOffset - oldestOffset > MULTIXACT_MEMBER_SAFE_THRESHOLD);
2650 }
MultiXactId nextMXact
Definition: multixact.c:203
#define DEBUG1
Definition: elog.h:25
uint32 MultiXactOffset
Definition: c.h:532
MultiXactOffset nextOffset
Definition: multixact.c:206
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:142
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition: multixact.c:2710
#define LOG
Definition: elog.h:26
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
MultiXactId oldestMultiXactId
Definition: multixact.c:216
MultiXactOffset offsetStopLimit
Definition: multixact.c:234
MultiXactOffset oldestOffset
Definition: multixact.c:224
#define ereport(elevel,...)
Definition: elog.h:144
TransactionId MultiXactId
Definition: c.h:530
#define Assert(condition)
Definition: c.h:745
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define SLRU_PAGES_PER_SEGMENT
Definition: slru.h:34
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:177

◆ SlruScanDirCbFindEarliest()

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

Definition at line 2844 of file multixact.c.

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

Referenced by TruncateMultiXact().

2845 {
2846  mxtruncinfo *trunc = (mxtruncinfo *) data;
2847 
2848  if (trunc->earliestExistingPage == -1 ||
2849  ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
2850  {
2851  trunc->earliestExistingPage = segpage;
2852  }
2853 
2854  return false; /* keep going */
2855 }
int earliestExistingPage
Definition: multixact.c:2836
bool(* PagePrecedes)(int, int)
Definition: slru.h:125

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 1984 of file multixact.c.

References MultiXactIdToOffsetPage, MultiXactMemberCtl, MultiXactOffsetCtl, MXOffsetToMemberPage, MultiXactStateData::nextMXact, and MultiXactStateData::nextOffset.

Referenced by StartupXLOG().

1985 {
1988  int pageno;
1989 
1990  /*
1991  * Initialize offset's idea of the latest page number.
1992  */
1993  pageno = MultiXactIdToOffsetPage(multi);
1994  MultiXactOffsetCtl->shared->latest_page_number = pageno;
1995 
1996  /*
1997  * Initialize member's idea of the latest page number.
1998  */
1999  pageno = MXOffsetToMemberPage(offset);
2000  MultiXactMemberCtl->shared->latest_page_number = pageno;
2001 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:532
MultiXactOffset nextOffset
Definition: multixact.c:206
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
#define MultiXactOffsetCtl
Definition: multixact.c:190
TransactionId MultiXactId
Definition: c.h:530
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 2007 of file multixact.c.

References MultiXactStateData::finishedStartup, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MemSet, MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberCtl, MultiXactOffsetCtl, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, SetMultiXactIdLimit(), and SimpleLruReadPage().

Referenced by StartupXLOG().

2008 {
2009  MultiXactId nextMXact;
2010  MultiXactOffset offset;
2011  MultiXactId oldestMXact;
2012  Oid oldestMXactDB;
2013  int pageno;
2014  int entryno;
2015  int flagsoff;
2016 
2017  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2018  nextMXact = MultiXactState->nextMXact;
2019  offset = MultiXactState->nextOffset;
2020  oldestMXact = MultiXactState->oldestMultiXactId;
2021  oldestMXactDB = MultiXactState->oldestMultiXactDB;
2022  LWLockRelease(MultiXactGenLock);
2023 
2024  /* Clean up offsets state */
2025  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
2026 
2027  /*
2028  * (Re-)Initialize our idea of the latest page number for offsets.
2029  */
2030  pageno = MultiXactIdToOffsetPage(nextMXact);
2031  MultiXactOffsetCtl->shared->latest_page_number = pageno;
2032 
2033  /*
2034  * Zero out the remainder of the current offsets page. See notes in
2035  * TrimCLOG() for background. Unlike CLOG, some WAL record covers every
2036  * pg_multixact SLRU mutation. Since, also unlike CLOG, we ignore the WAL
2037  * rule "write xlog before data," nextMXact successors may carry obsolete,
2038  * nonzero offset values. Zero those so case 2 of GetMultiXactIdMembers()
2039  * operates normally.
2040  */
2041  entryno = MultiXactIdToOffsetEntry(nextMXact);
2042  if (entryno != 0)
2043  {
2044  int slotno;
2045  MultiXactOffset *offptr;
2046 
2047  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2048  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2049  offptr += entryno;
2050 
2051  MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
2052 
2053  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2054  }
2055 
2056  LWLockRelease(MultiXactOffsetSLRULock);
2057 
2058  /* And the same for members */
2059  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
2060 
2061  /*
2062  * (Re-)Initialize our idea of the latest page number for members.
2063  */
2064  pageno = MXOffsetToMemberPage(offset);
2065  MultiXactMemberCtl->shared->latest_page_number = pageno;
2066 
2067  /*
2068  * Zero out the remainder of the current members page. See notes in
2069  * TrimCLOG() for motivation.
2070  */
2071  flagsoff = MXOffsetToFlagsOffset(offset);
2072  if (flagsoff != 0)
2073  {
2074  int slotno;
2075  TransactionId *xidptr;
2076  int memberoff;
2077 
2078  memberoff = MXOffsetToMemberOffset(offset);
2079  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2080  xidptr = (TransactionId *)
2081  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2082 
2083  MemSet(xidptr, 0, BLCKSZ - memberoff);
2084 
2085  /*
2086  * Note: we don't need to zero out the flag bits in the remaining
2087  * members of the current group, because they are always reset before
2088  * writing.
2089  */
2090 
2091  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2092  }
2093 
2094  LWLockRelease(MultiXactMemberSLRULock);
2095 
2096  /* signal that we're officially up */
2097  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2099  LWLockRelease(MultiXactGenLock);
2100 
2101  /* Now compute how far away the next members wraparound is. */
2102  SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2103 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:532
uint32 TransactionId
Definition: c.h:520
MultiXactOffset nextOffset
Definition: multixact.c:206
#define MemSet(start, val, len)
Definition: c.h:949
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
unsigned int Oid
Definition: postgres_ext.h:31
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define MXOffsetToMemberOffset(xid)
Definition: multixact.c:172
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:394
#define MultiXactOffsetCtl
Definition: multixact.c:190
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2189
TransactionId MultiXactId
Definition: c.h:530
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  newOldestMulti,
Oid  newOldestMultiDB 
)

Definition at line 2920 of file multixact.c.

References Assert, DEBUG1, PGPROC::delayChkpt, 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, MXOffsetToMemberSegment, MyProc, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, MultiXactStateData::oldestOffset, PerformMembersTruncation(), PerformOffsetsTruncation(), RecoveryInProgress(), SlruScanDirCbFindEarliest(), SlruScanDirectory(), START_CRIT_SECTION, and WriteMTruncateXlogRec().

Referenced by vac_truncate_clog().

2921 {
2922  MultiXactId oldestMulti;
2923  MultiXactId nextMulti;
2924  MultiXactOffset newOldestOffset;
2925  MultiXactOffset oldestOffset;
2926  MultiXactOffset nextOffset;
2927  mxtruncinfo trunc;
2928  MultiXactId earliest;
2929 
2932 
2933  /*
2934  * We can only allow one truncation to happen at once. Otherwise parts of
2935  * members might vanish while we're doing lookups or similar. There's no
2936  * need to have an interlock with creating new multis or such, since those
2937  * are constrained by the limits (which only grow, never shrink).
2938  */
2939  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
2940 
2941  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2942  nextMulti = MultiXactState->nextMXact;
2943  nextOffset = MultiXactState->nextOffset;
2944  oldestMulti = MultiXactState->oldestMultiXactId;
2945  LWLockRelease(MultiXactGenLock);
2946  Assert(MultiXactIdIsValid(oldestMulti));
2947 
2948  /*
2949  * Make sure to only attempt truncation if there's values to truncate
2950  * away. In normal processing values shouldn't go backwards, but there's
2951  * some corner cases (due to bugs) where that's possible.
2952  */
2953  if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
2954  {
2955  LWLockRelease(MultiXactTruncationLock);
2956  return;
2957  }
2958 
2959  /*
2960  * Note we can't just plow ahead with the truncation; it's possible that
2961  * there are no segments to truncate, which is a problem because we are
2962  * going to attempt to read the offsets page to determine where to
2963  * truncate the members SLRU. So we first scan the directory to determine
2964  * the earliest offsets page number that we can read without error.
2965  *
2966  * NB: It's also possible that the page that oldestMulti is on has already
2967  * been truncated away, and we crashed before updating oldestMulti.
2968  */
2969  trunc.earliestExistingPage = -1;
2972  if (earliest < FirstMultiXactId)
2973  earliest = FirstMultiXactId;
2974 
2975  /* If there's nothing to remove, we can bail out early. */
2976  if (MultiXactIdPrecedes(oldestMulti, earliest))
2977  {
2978  LWLockRelease(MultiXactTruncationLock);
2979  return;
2980  }
2981 
2982  /*
2983  * First, compute the safe truncation point for MultiXactMember. This is
2984  * the starting offset of the oldest multixact.
2985  *
2986  * Hopefully, find_multixact_start will always work here, because we've
2987  * already checked that it doesn't precede the earliest MultiXact on disk.
2988  * But if it fails, don't truncate anything, and log a message.
2989  */
2990  if (oldestMulti == nextMulti)
2991  {
2992  /* there are NO MultiXacts */
2993  oldestOffset = nextOffset;
2994  }
2995  else if (!find_multixact_start(oldestMulti, &oldestOffset))
2996  {
2997  ereport(LOG,
2998  (errmsg("oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
2999  oldestMulti, earliest)));
3000  LWLockRelease(MultiXactTruncationLock);
3001  return;
3002  }
3003 
3004  /*
3005  * Secondly compute up to where to truncate. Lookup the corresponding
3006  * member offset for newOldestMulti for that.
3007  */
3008  if (newOldestMulti == nextMulti)
3009  {
3010  /* there are NO MultiXacts */
3011  newOldestOffset = nextOffset;
3012  }
3013  else if (!find_multixact_start(newOldestMulti, &newOldestOffset))
3014  {
3015  ereport(LOG,
3016  (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
3017  newOldestMulti)));
3018  LWLockRelease(MultiXactTruncationLock);
3019  return;
3020  }
3021 
3022  elog(DEBUG1, "performing multixact truncation: "
3023  "offsets [%u, %u), offsets segments [%x, %x), "
3024  "members [%u, %u), members segments [%x, %x)",
3025  oldestMulti, newOldestMulti,
3026  MultiXactIdToOffsetSegment(oldestMulti),
3027  MultiXactIdToOffsetSegment(newOldestMulti),
3028  oldestOffset, newOldestOffset,
3029  MXOffsetToMemberSegment(oldestOffset),
3030  MXOffsetToMemberSegment(newOldestOffset));
3031 
3032  /*
3033  * Do truncation, and the WAL logging of the truncation, in a critical
3034  * section. That way offsets/members cannot get out of sync anymore, i.e.
3035  * once consistent the newOldestMulti will always exist in members, even
3036  * if we crashed in the wrong moment.
3037  */
3039 
3040  /*
3041  * Prevent checkpoints from being scheduled concurrently. This is critical
3042  * because otherwise a truncation record might not be replayed after a
3043  * crash/basebackup, even though the state of the data directory would
3044  * require it.
3045  */
3047  MyProc->delayChkpt = true;
3048 
3049  /* WAL log truncation */
3050  WriteMTruncateXlogRec(newOldestMultiDB,
3051  oldestMulti, newOldestMulti,
3052  oldestOffset, newOldestOffset);
3053 
3054  /*
3055  * Update in-memory limits before performing the truncation, while inside
3056  * the critical section: Have to do it before truncation, to prevent
3057  * concurrent lookups of those values. Has to be inside the critical
3058  * section as otherwise a future call to this function would error out,
3059  * while looking up the oldest member in offsets, if our caller crashes
3060  * before updating the limits.
3061  */
3062  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
3063  MultiXactState->oldestMultiXactId = newOldestMulti;
3064  MultiXactState->oldestMultiXactDB = newOldestMultiDB;
3065  LWLockRelease(MultiXactGenLock);
3066 
3067  /* First truncate members */
3068  PerformMembersTruncation(oldestOffset, newOldestOffset);
3069 
3070  /* Then offsets */
3071  PerformOffsetsTruncation(oldestMulti, newOldestMulti);
3072 
3073  MyProc->delayChkpt = false;
3074 
3075  END_CRIT_SECTION();
3076  LWLockRelease(MultiXactTruncationLock);
3077 }
MultiXactId nextMXact
Definition: multixact.c:203
#define DEBUG1
Definition: elog.h:25
static bool SlruScanDirCbFindEarliest(SlruCtl ctl, char *filename, int segpage, void *data)
Definition: multixact.c:2844
uint32 MultiXactOffset
Definition: c.h:532
PGPROC * MyProc
Definition: proc.c:67
MultiXactOffset nextOffset
Definition: multixact.c:206
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition: multixact.c:2710
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
#define LOG
Definition: elog.h:26
bool RecoveryInProgress(void)
Definition: xlog.c:8074
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
MultiXactId oldestMultiXactId
Definition: multixact.c:216
bool delayChkpt
Definition: proc.h:176
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2867
static void WriteMTruncateXlogRec(Oid oldestMultiDB, MultiXactId startTruncOff, MultiXactId endTruncOff, MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
Definition: multixact.c:3179
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define FirstMultiXactId
Definition: multixact.h:25
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define ereport(elevel,...)
Definition: elog.h:144
TransactionId MultiXactId
Definition: c.h:530
#define Assert(condition)
Definition: c.h:745
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1449
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3127
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3141
int earliestExistingPage
Definition: multixact.c:2836
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2895

◆ WriteMTruncateXlogRec()

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

Definition at line 3179 of file multixact.c.

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

3182 {
3183  XLogRecPtr recptr;
3184  xl_multixact_truncate xlrec;
3185 
3186  xlrec.oldestMultiDB = oldestMultiDB;
3187 
3188  xlrec.startTruncOff = startTruncOff;
3189  xlrec.endTruncOff = endTruncOff;
3190 
3191  xlrec.startTruncMemb = startTruncMemb;
3192  xlrec.endTruncMemb = endTruncMemb;
3193 
3194  XLogBeginInsert();
3195  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3196  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3197  XLogFlush(recptr);
3198 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2845
#define SizeOfMultiXactTruncate
Definition: multixact.h:100
MultiXactOffset endTruncMemb
Definition: multixact.h:97
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
MultiXactOffset startTruncMemb
Definition: multixact.h:96
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:75
MultiXactId startTruncOff
Definition: multixact.h:92
MultiXactId endTruncOff
Definition: multixact.h:93
void XLogBeginInsert(void)
Definition: xloginsert.c:123

◆ WriteMZeroPageXlogRec()

static void WriteMZeroPageXlogRec ( int  pageno,
uint8  info 
)
static

Definition at line 3165 of file multixact.c.

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

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

3166 {
3167  XLogBeginInsert();
3168  XLogRegisterData((char *) (&pageno), sizeof(int));
3169  (void) XLogInsert(RM_MULTIXACT_ID, info);
3170 }
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
void XLogBeginInsert(void)
Definition: xloginsert.c:123

◆ ZeroMultiXactMemberPage()

static int ZeroMultiXactMemberPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 1923 of file multixact.c.

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

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

1924 {
1925  int slotno;
1926 
1927  slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
1928 
1929  if (writeXlog)
1931 
1932  return slotno;
1933 }
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:73
static void WriteMZeroPageXlogRec(int pageno, uint8 info)
Definition: multixact.c:3165
#define MultiXactMemberCtl
Definition: multixact.c:191
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:279

◆ ZeroMultiXactOffsetPage()

static int ZeroMultiXactOffsetPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 1907 of file multixact.c.

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

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

1908 {
1909  int slotno;
1910 
1911  slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
1912 
1913  if (writeXlog)
1915 
1916  return slotno;
1917 }
static void WriteMZeroPageXlogRec(int pageno, uint8 info)
Definition: multixact.c:3165
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:72
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:279

Variable Documentation

◆ MultiXactMemberCtlData

SlruCtlData MultiXactMemberCtlData
static

Definition at line 188 of file multixact.c.

◆ MultiXactOffsetCtlData

SlruCtlData MultiXactOffsetCtlData
static

Definition at line 187 of file multixact.c.

◆ MultiXactState

MultiXactStateData* MultiXactState
static

Definition at line 291 of file multixact.c.

◆ MXactCache

dlist_head MXactCache = DLIST_STATIC_INIT(MXactCache)
static

Definition at line 322 of file multixact.c.

◆ MXactCacheMembers

int MXactCacheMembers = 0
static

Definition at line 323 of file multixact.c.

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

◆ MXactContext

MemoryContext MXactContext = NULL
static

Definition at line 324 of file multixact.c.

◆ OldestMemberMXactId

◆ OldestVisibleMXactId