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)
 
void ReadMultiXactIdRange (MultiXactId *oldest, MultiXactId *next)
 
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:575
#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:575
#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:575
#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:585
#define MaxOldestSlot
Definition: multixact.c:288
#define offsetof(type, field)
Definition: c.h:723

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

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

Referenced by AbortTransaction(), and CommitTransaction().

1684 {
1685  /*
1686  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1687  * which should only be valid while within a transaction.
1688  *
1689  * We assume that storing a MultiXactId is atomic and so we need not take
1690  * MultiXactGenLock to do this.
1691  */
1694 
1695  /*
1696  * Discard the local MultiXactId cache. Since MXactContext was created as
1697  * a child of TopTransactionContext, we needn't delete it explicitly.
1698  */
1699  MXactContext = NULL;
1701  MXactCacheMembers = 0;
1702 }
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 1712 of file multixact.c.

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

Referenced by PrepareTransaction().

1713 {
1714  MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1715 
1716  if (MultiXactIdIsValid(myOldestMember))
1718  &myOldestMember, sizeof(MultiXactId));
1719 }
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:585

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1889 of file multixact.c.

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

Referenced by BootStrapXLOG().

1890 {
1891  int slotno;
1892 
1893  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1894 
1895  /* Create and zero the first page of the offsets log */
1896  slotno = ZeroMultiXactOffsetPage(0, false);
1897 
1898  /* Make sure it's written out */
1900  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1901 
1902  LWLockRelease(MultiXactOffsetSLRULock);
1903 
1904  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
1905 
1906  /* Create and zero the first page of the members log */
1907  slotno = ZeroMultiXactMemberPage(0, false);
1908 
1909  /* Make sure it's written out */
1911  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1912 
1913  LWLockRelease(MultiXactMemberSLRULock);
1914 }
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1926
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:613
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:800
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1942
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2150 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

2151 {
2152  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2153 
2154  /*
2155  * Write dirty MultiXact pages to disk. This may result in sync requests
2156  * queued for later handling by ProcessSyncRequests(), as part of the
2157  * checkpoint.
2158  */
2161 
2162  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2163 }
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 2429 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().

2430 {
2431  /*
2432  * It's possible that the members span more than one page of the members
2433  * file, so we loop to ensure we consider each page. The coding is not
2434  * optimal if the members span several pages, but that seems unusual
2435  * enough to not worry much about.
2436  */
2437  while (nmembers > 0)
2438  {
2439  int flagsoff;
2440  int flagsbit;
2442 
2443  /*
2444  * Only zero when at first entry of a page.
2445  */
2446  flagsoff = MXOffsetToFlagsOffset(offset);
2447  flagsbit = MXOffsetToFlagsBitShift(offset);
2448  if (flagsoff == 0 && flagsbit == 0)
2449  {
2450  int pageno;
2451 
2452  pageno = MXOffsetToMemberPage(offset);
2453 
2454  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
2455 
2456  /* Zero the page and make an XLOG entry about it */
2457  ZeroMultiXactMemberPage(pageno, true);
2458 
2459  LWLockRelease(MultiXactMemberSLRULock);
2460  }
2461 
2462  /*
2463  * Compute the number of items till end of current page. Careful: if
2464  * addition of unsigned ints wraps around, we're at the last page of
2465  * the last segment; since that page holds a different number of items
2466  * than other pages, we need to do it differently.
2467  */
2468  if (offset + MAX_MEMBERS_IN_LAST_MEMBERS_PAGE < offset)
2469  {
2470  /*
2471  * This is the last page of the last segment; we can compute the
2472  * number of items left to allocate in it without modulo
2473  * arithmetic.
2474  */
2475  difference = MaxMultiXactOffset - offset + 1;
2476  }
2477  else
2479 
2480  /*
2481  * Advance to next page, taking care to properly handle the wraparound
2482  * case. OK if nmembers goes negative.
2483  */
2484  nmembers -= difference;
2485  offset += difference;
2486  }
2487 }
#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:1811
unsigned int uint32
Definition: c.h:429
Datum difference(PG_FUNCTION_ARGS)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1942
#define MAX_MEMBERS_IN_LAST_MEMBERS_PAGE
Definition: multixact.c:155

◆ ExtendMultiXactOffset()

static void ExtendMultiXactOffset ( MultiXactId  multi)
static

Definition at line 2399 of file multixact.c.

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

Referenced by GetNewMultiXactId().

2400 {
2401  int pageno;
2402 
2403  /*
2404  * No work except at first MultiXactId of a page. But beware: just after
2405  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2406  */
2407  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2408  multi != FirstMultiXactId)
2409  return;
2410 
2411  pageno = MultiXactIdToOffsetPage(multi);
2412 
2413  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
2414 
2415  /* Zero the page and make an XLOG entry about it */
2416  ZeroMultiXactOffsetPage(pageno, true);
2417 
2418  LWLockRelease(MultiXactOffsetSLRULock);
2419 }
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1926
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
#define FirstMultiXactId
Definition: multixact.h:25
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207

◆ find_multixact_start()

static bool find_multixact_start ( MultiXactId  multi,
MultiXactOffset result 
)
static

Definition at line 2729 of file multixact.c.

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

Referenced by SetOffsetVacuumLimit(), and TruncateMultiXact().

2730 {
2731  MultiXactOffset offset;
2732  int pageno;
2733  int entryno;
2734  int slotno;
2735  MultiXactOffset *offptr;
2736 
2738 
2739  pageno = MultiXactIdToOffsetPage(multi);
2740  entryno = MultiXactIdToOffsetEntry(multi);
2741 
2742  /*
2743  * Write out dirty data, so PhysicalPageExists can work correctly.
2744  */
2747 
2749  return false;
2750 
2751  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2752  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2753  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2754  offptr += entryno;
2755  offset = *offptr;
2756  LWLockRelease(MultiXactOffsetSLRULock);
2757 
2758  *result = offset;
2759  return true;
2760 }
uint32 MultiXactOffset
Definition: c.h:587
#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:1811
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:800
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ GetMultiXactIdMembers()

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

Definition at line 1223 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().

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

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

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2501 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().

2502 {
2503  MultiXactId oldestMXact;
2504  MultiXactId nextMXact;
2505  int i;
2506 
2507  /*
2508  * This is the oldest valid value among all the OldestMemberMXactId[] and
2509  * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2510  */
2511  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2512 
2513  /*
2514  * We have to beware of the possibility that nextMXact is in the
2515  * wrapped-around state. We don't fix the counter itself here, but we
2516  * must be sure to use a valid value in our calculation.
2517  */
2518  nextMXact = MultiXactState->nextMXact;
2519  if (nextMXact < FirstMultiXactId)
2520  nextMXact = FirstMultiXactId;
2521 
2522  oldestMXact = nextMXact;
2523  for (i = 1; i <= MaxOldestSlot; i++)
2524  {
2525  MultiXactId thisoldest;
2526 
2527  thisoldest = OldestMemberMXactId[i];
2528  if (MultiXactIdIsValid(thisoldest) &&
2529  MultiXactIdPrecedes(thisoldest, oldestMXact))
2530  oldestMXact = thisoldest;
2531  thisoldest = OldestVisibleMXactId[i];
2532  if (MultiXactIdIsValid(thisoldest) &&
2533  MultiXactIdPrecedes(thisoldest, oldestMXact))
2534  oldestMXact = thisoldest;
2535  }
2536 
2537  LWLockRelease(MultiXactGenLock);
2538 
2539  return oldestMXact;
2540 }
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:1811
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define FirstMultiXactId
Definition: multixact.h:25
TransactionId MultiXactId
Definition: c.h:585
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3146
int i
#define MaxOldestSlot
Definition: multixact.c:288

◆ MaybeExtendOffsetSlru()

static void MaybeExtendOffsetSlru ( void  )
static

Definition at line 1970 of file multixact.c.

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

Referenced by MultiXactSetNextMXact().

1971 {
1972  int pageno;
1973 
1975 
1976  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1977 
1979  {
1980  int slotno;
1981 
1982  /*
1983  * Fortunately for us, SimpleLruWritePage is already prepared to deal
1984  * with creating a new segment file even if the page we're writing is
1985  * not the first in it, so this is enough.
1986  */
1987  slotno = ZeroMultiXactOffsetPage(pageno, false);
1989  }
1990 
1991  LWLockRelease(MultiXactOffsetSLRULock);
1992 }
MultiXactId nextMXact
Definition: multixact.c:203
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1926
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
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:1207

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 3223 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().

3224 {
3225  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3226 
3227  /* Backup blocks are not used in multixact records */
3228  Assert(!XLogRecHasAnyBlockRefs(record));
3229 
3230  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3231  {
3232  int pageno;
3233  int slotno;
3234 
3235  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3236 
3237  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
3238 
3239  slotno = ZeroMultiXactOffsetPage(pageno, false);
3241  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3242 
3243  LWLockRelease(MultiXactOffsetSLRULock);
3244  }
3245  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3246  {
3247  int pageno;
3248  int slotno;
3249 
3250  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3251 
3252  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
3253 
3254  slotno = ZeroMultiXactMemberPage(pageno, false);
3256  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3257 
3258  LWLockRelease(MultiXactMemberSLRULock);
3259  }
3260  else if (info == XLOG_MULTIXACT_CREATE_ID)
3261  {
3262  xl_multixact_create *xlrec =
3263  (xl_multixact_create *) XLogRecGetData(record);
3264  TransactionId max_xid;
3265  int i;
3266 
3267  /* Store the data back into the SLRU files */
3268  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3269  xlrec->members);
3270 
3271  /* Make sure nextMXact/nextOffset are beyond what this record has */
3272  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3273  xlrec->moff + xlrec->nmembers);
3274 
3275  /*
3276  * Make sure nextXid is beyond any XID mentioned in the record.
3277  * This should be unnecessary, since any XID found here ought to have
3278  * other evidence in the XLOG, but let's be safe.
3279  */
3280  max_xid = XLogRecGetXid(record);
3281  for (i = 0; i < xlrec->nmembers; i++)
3282  {
3283  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3284  max_xid = xlrec->members[i].xid;
3285  }
3286 
3288  }
3289  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3290  {
3291  xl_multixact_truncate xlrec;
3292  int pageno;
3293 
3294  memcpy(&xlrec, XLogRecGetData(record),
3296 
3297  elog(DEBUG1, "replaying multixact truncation: "
3298  "offsets [%u, %u), offsets segments [%x, %x), "
3299  "members [%u, %u), members segments [%x, %x)",
3300  xlrec.startTruncOff, xlrec.endTruncOff,
3303  xlrec.startTruncMemb, xlrec.endTruncMemb,
3306 
3307  /* should not be required, but more than cheap enough */
3308  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3309 
3310  /*
3311  * Advance the horizon values, so they're current at the end of
3312  * recovery.
3313  */
3314  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3315 
3317 
3318  /*
3319  * During XLOG replay, latest_page_number isn't necessarily set up
3320  * yet; insert a suitable value to bypass the sanity test in
3321  * SimpleLruTruncate.
3322  */
3323  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3324  MultiXactOffsetCtl->shared->latest_page_number = pageno;
3326 
3327  LWLockRelease(MultiXactTruncationLock);
3328  }
3329  else
3330  elog(PANIC, "multixact_redo: unknown op code %u", info);
3331 }
#define DEBUG1
Definition: elog.h:25
uint32 TransactionId
Definition: c.h:575
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:277
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1926
unsigned char uint8
Definition: c.h:427
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:73
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2357
#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:1811
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:2886
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:2208
MultiXactId mid
Definition: multixact.h:79
#define Assert(condition)
Definition: c.h:800
#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:1207
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1942
#define elog(elevel,...)
Definition: elog.h:228
int i
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:312
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:862
MultiXactId endTruncOff
Definition: multixact.h:93
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2914
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ multixact_twophase_postabort()

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

Definition at line 1812 of file multixact.c.

References multixact_twophase_postcommit().

1814 {
1815  multixact_twophase_postcommit(xid, info, recdata, len);
1816 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1797

◆ multixact_twophase_postcommit()

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

Definition at line 1797 of file multixact.c.

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

Referenced by multixact_twophase_postabort().

1799 {
1800  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, true);
1801 
1802  Assert(len == sizeof(MultiXactId));
1803 
1804  OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
1805 }
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:585
#define Assert(condition)
Definition: c.h:800

◆ multixact_twophase_recover()

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

Definition at line 1776 of file multixact.c.

References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

1778 {
1779  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1780  MultiXactId oldestMember;
1781 
1782  /*
1783  * Get the oldest member XID from the state file record, and set it in the
1784  * OldestMemberMXactId slot reserved for this prepared transaction.
1785  */
1786  Assert(len == sizeof(MultiXactId));
1787  oldestMember = *((MultiXactId *) recdata);
1788 
1789  OldestMemberMXactId[dummyBackendId] = oldestMember;
1790 }
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:585
#define Assert(condition)
Definition: c.h:800

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2357 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().

2359 {
2360  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2362  {
2363  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2364  MultiXactState->nextMXact = minMulti;
2365  }
2366  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2367  {
2368  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2369  minMultiOffset);
2370  MultiXactState->nextOffset = minMultiOffset;
2371  }
2372  LWLockRelease(MultiXactGenLock);
2373 }
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:1811
#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:1207
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3146
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3172

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2382 of file multixact.c.

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

Referenced by xlog_redo().

2383 {
2384  Assert(InRecovery);
2385 
2387  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2388 }
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:2208
#define Assert(condition)
Definition: c.h:800
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3146

◆ MultiXactGetCheckptMulti()

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

Definition at line 2128 of file multixact.c.

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

Referenced by CreateCheckPoint().

2133 {
2134  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2135  *nextMulti = MultiXactState->nextMXact;
2136  *nextMultiOffset = MultiXactState->nextOffset;
2137  *oldestMulti = MultiXactState->oldestMultiXactId;
2138  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2139  LWLockRelease(MultiXactGenLock);
2140 
2142  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2143  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2144 }
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:1811
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:1207

◆ 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:767
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:1652
#define AssertArg(condition)
Definition: c.h:802
#define debug_elog3(a, b, c)
Definition: multixact.c:334
TransactionId MultiXactId
Definition: c.h:585
#define Assert(condition)
Definition: c.h:800
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 767 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().

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

◆ 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:1322
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:767
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:802
#define debug_elog3(a, b, c)
Definition: multixact.c:334
TransactionId MultiXactId
Definition: c.h:585
#define Assert(condition)
Definition: c.h:800
void * palloc(Size size)
Definition: mcxt.c:950
int i
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1629
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1223
#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:1322
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:1223

◆ MultiXactIdPrecedes()

◆ MultiXactIdPrecedesOrEquals()

bool MultiXactIdPrecedesOrEquals ( MultiXactId  multi1,
MultiXactId  multi2 
)

Definition at line 3160 of file multixact.c.

Referenced by check_mxid_in_range(), heap_vacuum_rel(), and TruncateMultiXact().

3161 {
3162  int32 diff = (int32) (multi1 - multi2);
3163 
3164  return (diff <= 0);
3165 }
signed int int32
Definition: c.h:417

◆ 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:1811
#define DEBUG2
Definition: elog.h:24
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define FirstMultiXactId
Definition: multixact.h:25
TransactionId MultiXactId
Definition: c.h:585
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207

◆ 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:1811
#define DEBUG2
Definition: elog.h:24
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
#define FirstMultiXactId
Definition: multixact.h:25
TransactionId MultiXactId
Definition: c.h:585
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3146
int i
#define MaxOldestSlot
Definition: multixact.c:288

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2823 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().

2824 {
2825  MultiXactOffset members;
2826  uint32 multixacts;
2827  uint32 victim_multixacts;
2828  double fraction;
2829 
2830  /* If we can't determine member space utilization, assume the worst. */
2831  if (!ReadMultiXactCounts(&multixacts, &members))
2832  return 0;
2833 
2834  /* If member space utilization is low, no special action is required. */
2835  if (members <= MULTIXACT_MEMBER_SAFE_THRESHOLD)
2837 
2838  /*
2839  * Compute a target for relminmxid advancement. The number of multixacts
2840  * we try to eliminate from the system is based on how far we are past
2841  * MULTIXACT_MEMBER_SAFE_THRESHOLD.
2842  */
2843  fraction = (double) (members - MULTIXACT_MEMBER_SAFE_THRESHOLD) /
2845  victim_multixacts = multixacts * fraction;
2846 
2847  /* fraction could be > 1.0, but lowest possible freeze age is zero */
2848  if (victim_multixacts > multixacts)
2849  return 0;
2850  return multixacts - victim_multixacts;
2851 }
#define MULTIXACT_MEMBER_DANGER_THRESHOLD
Definition: multixact.c:178
uint32 MultiXactOffset
Definition: c.h:587
int autovacuum_multixact_freeze_max_age
Definition: autovacuum.c:125
unsigned int uint32
Definition: c.h:429
static bool ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
Definition: multixact.c:2767
#define MULTIXACT_MEMBER_SAFE_THRESHOLD
Definition: multixact.c:177

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 3128 of file multixact.c.

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

3129 {
3130  MultiXactOffset offset1;
3131  MultiXactOffset offset2;
3132 
3133  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3134  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3135 
3136  return MultiXactOffsetPrecedes(offset1, offset2);
3137 }
uint32 MultiXactOffset
Definition: c.h:587
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:142
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3172

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3411 of file multixact.c.

References MultiXactMemberCtl, and SlruSyncFileTag().

3412 {
3413  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3414 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1481
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 3110 of file multixact.c.

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

3111 {
3112  MultiXactId multi1;
3113  MultiXactId multi2;
3114 
3115  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3116  multi1 += FirstMultiXactId;
3117  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3118  multi2 += FirstMultiXactId;
3119 
3120  return MultiXactIdPrecedes(multi1, multi2);
3121 }
#define FirstMultiXactId
Definition: multixact.h:25
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
TransactionId MultiXactId
Definition: c.h:585
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3146

◆ MultiXactOffsetPrecedes()

static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3172 of file multixact.c.

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

3173 {
3174  int32 diff = (int32) (offset1 - offset2);
3175 
3176  return (diff < 0);
3177 }
signed int int32
Definition: c.h:417

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3402 of file multixact.c.

References MultiXactOffsetCtl, and SlruSyncFileTag().

3403 {
3404  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3405 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1481
#define MultiXactOffsetCtl
Definition: multixact.c:190

◆ MultiXactOffsetWouldWrap()

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

Definition at line 2681 of file multixact.c.

Referenced by GetNewMultiXactId().

2683 {
2684  MultiXactOffset finish;
2685 
2686  /*
2687  * Note that offset number 0 is not used (see GetMultiXactIdMembers), so
2688  * if the addition wraps around the UINT_MAX boundary, skip that value.
2689  */
2690  finish = start + distance;
2691  if (finish < start)
2692  finish++;
2693 
2694  /*-----------------------------------------------------------------------
2695  * When the boundary is numerically greater than the starting point, any
2696  * value numerically between the two is not wrapped:
2697  *
2698  * <----S----B---->
2699  * [---) = F wrapped past B (and UINT_MAX)
2700  * [---) = F not wrapped
2701  * [----] = F wrapped past B
2702  *
2703  * When the boundary is numerically less than the starting point (i.e. the
2704  * UINT_MAX wraparound occurs somewhere in between) then all values in
2705  * between are wrapped:
2706  *
2707  * <----B----S---->
2708  * [---) = F not wrapped past B (but wrapped past UINT_MAX)
2709  * [---) = F wrapped past B (and UINT_MAX)
2710  * [----] = F not wrapped
2711  *-----------------------------------------------------------------------
2712  */
2713  if (start < boundary)
2714  return finish >= boundary || finish < start;
2715  else
2716  return finish >= boundary && finish < start;
2717 }
uint32 MultiXactOffset
Definition: c.h:587

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2174 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().

2176 {
2177  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2178  nextMulti, nextMultiOffset);
2179  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2180  MultiXactState->nextMXact = nextMulti;
2181  MultiXactState->nextOffset = nextMultiOffset;
2182  LWLockRelease(MultiXactGenLock);
2183 
2184  /*
2185  * During a binary upgrade, make sure that the offsets SLRU is large
2186  * enough to contain the next value that would be created.
2187  *
2188  * We need to do this pretty early during the first startup in binary
2189  * upgrade mode: before StartupMultiXact() in fact, because this routine
2190  * is called even before that by StartupXLOG(). And we can't do it
2191  * earlier than at this point, because during that first call of this
2192  * routine we determine the MultiXactState->nextMXact value that
2193  * MaybeExtendOffsetSlru needs.
2194  */
2195  if (IsBinaryUpgrade)
2197 }
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:1970
bool IsBinaryUpgrade
Definition: globals.c:110
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
#define DEBUG2
Definition: elog.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207

◆ MultiXactShmemInit()

void MultiXactShmemInit ( void  )

Definition at line 1841 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().

1842 {
1843  bool found;
1844 
1845  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1846 
1849 
1851  "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
1852  MultiXactOffsetSLRULock, "pg_multixact/offsets",
1856  "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
1857  MultiXactMemberSLRULock, "pg_multixact/members",
1860 
1861  /* Initialize our shared state struct */
1862  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1864  &found);
1865  if (!IsUnderPostmaster)
1866  {
1867  Assert(!found);
1868 
1869  /* Make sure we zero out the per-backend state */
1871  }
1872  else
1873  Assert(found);
1874 
1875  /*
1876  * Set up array pointers. Note that perBackendXactIds[0] is wasted space
1877  * since we only use indexes 1..MaxOldestSlot in each array.
1878  */
1881 }
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:3110
#define MemSet(start, val, len)
Definition: c.h:1004
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:3128
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:800
#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 1824 of file multixact.c.

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

Referenced by CreateSharedMemoryAndSemaphores().

1825 {
1826  Size size;
1827 
1828  /* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
1829 #define SHARED_MULTIXACT_STATE_SIZE \
1830  add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
1831  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1832 
1836 
1837  return size;
1838 }
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:528
#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 1536 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().

1537 {
1538  dlist_iter iter;
1539 
1540  debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1541 
1542  dlist_foreach(iter, &MXactCache)
1543  {
1544  mXactCacheEnt *entry = dlist_container(mXactCacheEnt, node, iter.cur);
1545 
1546  if (entry->multi == multi)
1547  {
1548  MultiXactMember *ptr;
1549  Size size;
1550 
1551  size = sizeof(MultiXactMember) * entry->nmembers;
1552  ptr = (MultiXactMember *) palloc(size);
1553  *members = ptr;
1554 
1555  memcpy(ptr, entry->members, size);
1556 
1557  debug_elog3(DEBUG2, "CacheGet: found %s",
1558  mxid_to_string(multi,
1559  entry->nmembers,
1560  entry->members));
1561 
1562  /*
1563  * Note we modify the list while not using a modifiable iterator.
1564  * This is acceptable only because we exit the iteration
1565  * immediately afterwards.
1566  */
1567  dlist_move_head(&MXactCache, iter.cur);
1568 
1569  return entry->nmembers;
1570  }
1571  }
1572 
1573  debug_elog2(DEBUG2, "CacheGet: not found");
1574  return -1;
1575 }
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:1652
#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:528
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 1494 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().

1495 {
1496  dlist_iter iter;
1497 
1498  debug_elog3(DEBUG2, "CacheGet: looking for %s",
1499  mxid_to_string(InvalidMultiXactId, nmembers, members));
1500 
1501  /* sort the array so comparison is easy */
1502  qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1503 
1504  dlist_foreach(iter, &MXactCache)
1505  {
1506  mXactCacheEnt *entry = dlist_container(mXactCacheEnt, node, iter.cur);
1507 
1508  if (entry->nmembers != nmembers)
1509  continue;
1510 
1511  /*
1512  * We assume the cache entries are sorted, and that the unused bits in
1513  * "status" are zeroed.
1514  */
1515  if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1516  {
1517  debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1518  dlist_move_head(&MXactCache, iter.cur);
1519  return entry->multi;
1520  }
1521  }
1522 
1523  debug_elog2(DEBUG2, "CacheGet: not found :-(");
1524  return InvalidMultiXactId;
1525 }
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:1652
#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:1464
#define qsort(a, b, c, d)
Definition: port.h:497
MultiXactId multi
Definition: multixact.c:315

◆ mXactCachePut()

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

Definition at line 1582 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().

1583 {
1584  mXactCacheEnt *entry;
1585 
1586  debug_elog3(DEBUG2, "CachePut: storing %s",
1587  mxid_to_string(multi, nmembers, members));
1588 
1589  if (MXactContext == NULL)
1590  {
1591  /* The cache only lives as long as the current transaction */
1592  debug_elog2(DEBUG2, "CachePut: initializing memory context");
1594  "MultiXact cache context",
1596  }
1597 
1598  entry = (mXactCacheEnt *)
1600  offsetof(mXactCacheEnt, members) +
1601  nmembers * sizeof(MultiXactMember));
1602 
1603  entry->multi = multi;
1604  entry->nmembers = nmembers;
1605  memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1606 
1607  /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1608  qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1609 
1610  dlist_push_head(&MXactCache, &entry->node);
1612  {
1613  dlist_node *node;
1614  mXactCacheEnt *entry;
1615 
1616  node = dlist_tail_node(&MXactCache);
1617  dlist_delete(node);
1619 
1620  entry = dlist_container(mXactCacheEnt, node, node);
1621  debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1622  entry->multi);
1623 
1624  pfree(entry);
1625  }
1626 }
#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:1652
#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:1464
static MemoryContext MXactContext
Definition: multixact.c:324
#define qsort(a, b, c, d)
Definition: port.h:497
MultiXactId multi
Definition: multixact.c:315
#define offsetof(type, field)
Definition: c.h:723

◆ mxactMemberComparator()

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

Definition at line 1464 of file multixact.c.

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

Referenced by mXactCacheGetBySet(), and mXactCachePut().

1465 {
1466  MultiXactMember member1 = *(const MultiXactMember *) arg1;
1467  MultiXactMember member2 = *(const MultiXactMember *) arg2;
1468 
1469  if (member1.xid > member2.xid)
1470  return 1;
1471  if (member1.xid < member2.xid)
1472  return -1;
1473  if (member1.status > member2.status)
1474  return 1;
1475  if (member1.status < member2.status)
1476  return -1;
1477  return 0;
1478 }
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 1652 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().

1653 {
1654  static char *str = NULL;
1656  int i;
1657 
1658  if (str != NULL)
1659  pfree(str);
1660 
1661  initStringInfo(&buf);
1662 
1663  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1664  mxstatus_to_string(members[0].status));
1665 
1666  for (i = 1; i < nmembers; i++)
1667  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1668  mxstatus_to_string(members[i].status));
1669 
1670  appendStringInfoChar(&buf, ']');
1672  pfree(buf.data);
1673  return str;
1674 }
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:68
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:1629
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 1629 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().

1630 {
1631  switch (status)
1632  {
1634  return "keysh";
1636  return "sh";
1638  return "fornokeyupd";
1640  return "forupd";
1642  return "nokeyupd";
1643  case MultiXactStatusUpdate:
1644  return "upd";
1645  default:
1646  elog(ERROR, "unrecognized multixact status %d", status);
1647  return "";
1648  }
1649 }
#define ERROR
Definition: elog.h:43
#define elog(elevel,...)
Definition: elog.h:228
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 2886 of file multixact.c.

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

Referenced by multixact_redo(), and TruncateMultiXact().

2887 {
2888  const int maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
2889  int startsegment = MXOffsetToMemberSegment(oldestOffset);
2890  int endsegment = MXOffsetToMemberSegment(newOldestOffset);
2891  int segment = startsegment;
2892 
2893  /*
2894  * Delete all the segments but the last one. The last segment can still
2895  * contain, possibly partially, valid data.
2896  */
2897  while (segment != endsegment)
2898  {
2899  elog(DEBUG2, "truncating multixact members segment %x", segment);
2901 
2902  /* move to next segment, handling wraparound correctly */
2903  if (segment == maxsegment)
2904  segment = 0;
2905  else
2906  segment += 1;
2907  }
2908 }
#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:228
void SlruDeleteSegment(SlruCtl ctl, int segno)
Definition: slru.c:1330
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ PerformOffsetsTruncation()

static void PerformOffsetsTruncation ( MultiXactId  oldestMulti,
MultiXactId  newOldestMulti 
)
static

Definition at line 2914 of file multixact.c.

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

Referenced by multixact_redo(), and TruncateMultiXact().

2915 {
2916  /*
2917  * We step back one multixact to avoid passing a cutoff page that hasn't
2918  * been created yet in the rare case that oldestMulti would be the first
2919  * item on a page and oldestMulti == nextMulti. In that case, if we
2920  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
2921  * detection.
2922  */
2924  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
2925 }
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 3334 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_TRANSACTIONID, psprintf(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, TupleDescGetAttInMetadata(), TupleDescInitEntry(), FuncCallContext::user_fctx, and values.

3335 {
3336  typedef struct
3337  {
3338  MultiXactMember *members;
3339  int nmembers;
3340  int iter;
3341  } mxact;
3343  mxact *multi;
3344  FuncCallContext *funccxt;
3345 
3346  if (mxid < FirstMultiXactId)
3347  ereport(ERROR,
3348  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3349  errmsg("invalid MultiXactId: %u", mxid)));
3350 
3351  if (SRF_IS_FIRSTCALL())
3352  {
3353  MemoryContext oldcxt;
3354  TupleDesc tupdesc;
3355 
3356  funccxt = SRF_FIRSTCALL_INIT();
3357  oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3358 
3359  multi = palloc(sizeof(mxact));
3360  /* no need to allow for old values here */
3361  multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3362  false);
3363  multi->iter = 0;
3364 
3365  tupdesc = CreateTemplateTupleDesc(2);
3366  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid",
3367  XIDOID, -1, 0);
3368  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "mode",
3369  TEXTOID, -1, 0);
3370 
3371  funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3372  funccxt->user_fctx = multi;
3373 
3374  MemoryContextSwitchTo(oldcxt);
3375  }
3376 
3377  funccxt = SRF_PERCALL_SETUP();
3378  multi = (mxact *) funccxt->user_fctx;
3379 
3380  while (multi->iter < multi->nmembers)
3381  {
3382  HeapTuple tuple;
3383  char *values[2];
3384 
3385  values[0] = psprintf("%u", multi->members[multi->iter].xid);
3386  values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3387 
3388  tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3389 
3390  multi->iter++;
3391  pfree(values[0]);
3392  SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3393  }
3394 
3395  SRF_RETURN_DONE(funccxt);
3396 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:294
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:691
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:298
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2116
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:300
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ERROR
Definition: elog.h:43
#define PG_GETARG_TRANSACTIONID(n)
Definition: fmgr.h:279
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:155
TransactionId MultiXactId
Definition: c.h:585
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
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:902
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1629
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1223
int16 AttrNumber
Definition: attnum.h:21
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:318
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:296

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1726 of file multixact.c.

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

Referenced by PrepareTransaction().

1727 {
1728  MultiXactId myOldestMember;
1729 
1730  /*
1731  * Transfer our OldestMemberMXactId value to the slot reserved for the
1732  * prepared transaction.
1733  */
1734  myOldestMember = OldestMemberMXactId[MyBackendId];
1735  if (MultiXactIdIsValid(myOldestMember))
1736  {
1737  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1738 
1739  /*
1740  * Even though storing MultiXactId is atomic, acquire lock to make
1741  * sure others see both changes, not just the reset of the slot of the
1742  * current backend. Using a volatile pointer might suffice, but this
1743  * isn't a hot spot.
1744  */
1745  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1746 
1747  OldestMemberMXactId[dummyBackendId] = myOldestMember;
1749 
1750  LWLockRelease(MultiXactGenLock);
1751  }
1752 
1753  /*
1754  * We don't need to transfer OldestVisibleMXactId value, because the
1755  * transaction is not going to be looking at any more multixacts once it's
1756  * prepared.
1757  *
1758  * We assume that storing a MultiXactId is atomic and so we need not take
1759  * MultiXactGenLock to do this.
1760  */
1762 
1763  /*
1764  * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1765  */
1766  MXactContext = NULL;
1768  MXactCacheMembers = 0;
1769 }
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:1811
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:585
static dlist_head MXactCache
Definition: multixact.c:322
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
static MemoryContext MXactContext
Definition: multixact.c:324

◆ ReadMultiXactCounts()

static bool ReadMultiXactCounts ( uint32 multixacts,
MultiXactOffset members 
)
static

Definition at line 2767 of file multixact.c.

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

Referenced by MultiXactMemberFreezeThreshold().

2768 {
2769  MultiXactOffset nextOffset;
2770  MultiXactOffset oldestOffset;
2771  MultiXactId oldestMultiXactId;
2772  MultiXactId nextMultiXactId;
2773  bool oldestOffsetKnown;
2774 
2775  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2776  nextOffset = MultiXactState->nextOffset;
2777  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2778  nextMultiXactId = MultiXactState->nextMXact;
2779  oldestOffset = MultiXactState->oldestOffset;
2780  oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2781  LWLockRelease(MultiXactGenLock);
2782 
2783  if (!oldestOffsetKnown)
2784  return false;
2785 
2786  *members = nextOffset - oldestOffset;
2787  *multixacts = nextMultiXactId - oldestMultiXactId;
2788  return true;
2789 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:587
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
MultiXactId oldestMultiXactId
Definition: multixact.c:216
MultiXactOffset oldestOffset
Definition: multixact.c:224
TransactionId MultiXactId
Definition: c.h:585
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 743 of file multixact.c.

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

Referenced by update_cached_mxid_range().

744 {
745  LWLockAcquire(MultiXactGenLock, LW_SHARED);
748  LWLockRelease(MultiXactGenLock);
749 
750  if (*oldest < FirstMultiXactId)
751  *oldest = FirstMultiXactId;
752  if (*next < FirstMultiXactId)
754 }
MultiXactId nextMXact
Definition: multixact.c:203
static int32 next
Definition: blutils.c:219
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1811
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define FirstMultiXactId
Definition: multixact.h:25
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207

◆ 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:1811
#define FirstMultiXactId
Definition: multixact.h:25
TransactionId MultiXactId
Definition: c.h:585
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207

◆ RecordNewMultiXact()

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

Definition at line 862 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().

864 {
865  int pageno;
866  int prev_pageno;
867  int entryno;
868  int slotno;
869  MultiXactOffset *offptr;
870  int i;
871 
872  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
873 
874  pageno = MultiXactIdToOffsetPage(multi);
875  entryno = MultiXactIdToOffsetEntry(multi);
876 
877  /*
878  * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
879  * to complain about if there's any I/O error. This is kinda bogus, but
880  * since the errors will always give the full pathname, it should be clear
881  * enough that a MultiXactId is really involved. Perhaps someday we'll
882  * take the trouble to generalize the slru.c error reporting code.
883  */
884  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
885  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
886  offptr += entryno;
887 
888  *offptr = offset;
889 
890  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
891 
892  /* Exchange our lock */
893  LWLockRelease(MultiXactOffsetSLRULock);
894 
895  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
896 
897  prev_pageno = -1;
898 
899  for (i = 0; i < nmembers; i++, offset++)
900  {
901  TransactionId *memberptr;
902  uint32 *flagsptr;
903  uint32 flagsval;
904  int bshift;
905  int flagsoff;
906  int memberoff;
907 
908  Assert(members[i].status <= MultiXactStatusUpdate);
909 
910  pageno = MXOffsetToMemberPage(offset);
911  memberoff = MXOffsetToMemberOffset(offset);
912  flagsoff = MXOffsetToFlagsOffset(offset);
913  bshift = MXOffsetToFlagsBitShift(offset);
914 
915  if (pageno != prev_pageno)
916  {
917  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
918  prev_pageno = pageno;
919  }
920 
921  memberptr = (TransactionId *)
922  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
923 
924  *memberptr = members[i].xid;
925 
926  flagsptr = (uint32 *)
927  (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
928 
929  flagsval = *flagsptr;
930  flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
931  flagsval |= (members[i].status << bshift);
932  *flagsptr = flagsval;
933 
934  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
935  }
936 
937  LWLockRelease(MultiXactMemberSLRULock);
938 }
#define MXOffsetToFlagsBitShift(xid)
Definition: multixact.c:167
uint32 MultiXactOffset
Definition: c.h:587
uint32 TransactionId
Definition: c.h:575
#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:1811
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:429
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:800
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
#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 2208 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().

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

◆ SetOffsetVacuumLimit()

static bool SetOffsetVacuumLimit ( bool  is_startup)
static

Definition at line 2554 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().

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

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

Referenced by TruncateMultiXact().

2864 {
2865  mxtruncinfo *trunc = (mxtruncinfo *) data;
2866 
2867  if (trunc->earliestExistingPage == -1 ||
2868  ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
2869  {
2870  trunc->earliestExistingPage = segpage;
2871  }
2872 
2873  return false; /* keep going */
2874 }
int earliestExistingPage
Definition: multixact.c:2855
bool(* PagePrecedes)(int, int)
Definition: slru.h:125

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2003 of file multixact.c.

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

Referenced by StartupXLOG().

2004 {
2007  int pageno;
2008 
2009  /*
2010  * Initialize offset's idea of the latest page number.
2011  */
2012  pageno = MultiXactIdToOffsetPage(multi);
2013  MultiXactOffsetCtl->shared->latest_page_number = pageno;
2014 
2015  /*
2016  * Initialize member's idea of the latest page number.
2017  */
2018  pageno = MXOffsetToMemberPage(offset);
2019  MultiXactMemberCtl->shared->latest_page_number = pageno;
2020 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:587
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:585
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 2026 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().

2027 {
2028  MultiXactId nextMXact;
2029  MultiXactOffset offset;
2030  MultiXactId oldestMXact;
2031  Oid oldestMXactDB;
2032  int pageno;
2033  int entryno;
2034  int flagsoff;
2035 
2036  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2037  nextMXact = MultiXactState->nextMXact;
2038  offset = MultiXactState->nextOffset;
2039  oldestMXact = MultiXactState->oldestMultiXactId;
2040  oldestMXactDB = MultiXactState->oldestMultiXactDB;
2041  LWLockRelease(MultiXactGenLock);
2042 
2043  /* Clean up offsets state */
2044  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
2045 
2046  /*
2047  * (Re-)Initialize our idea of the latest page number for offsets.
2048  */
2049  pageno = MultiXactIdToOffsetPage(nextMXact);
2050  MultiXactOffsetCtl->shared->latest_page_number = pageno;
2051 
2052  /*
2053  * Zero out the remainder of the current offsets page. See notes in
2054  * TrimCLOG() for background. Unlike CLOG, some WAL record covers every
2055  * pg_multixact SLRU mutation. Since, also unlike CLOG, we ignore the WAL
2056  * rule "write xlog before data," nextMXact successors may carry obsolete,
2057  * nonzero offset values. Zero those so case 2 of GetMultiXactIdMembers()
2058  * operates normally.
2059  */
2060  entryno = MultiXactIdToOffsetEntry(nextMXact);
2061  if (entryno != 0)
2062  {
2063  int slotno;
2064  MultiXactOffset *offptr;
2065 
2066  slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
2067  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2068  offptr += entryno;
2069 
2070  MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset)));
2071 
2072  MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
2073  }
2074 
2075  LWLockRelease(MultiXactOffsetSLRULock);
2076 
2077  /* And the same for members */
2078  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
2079 
2080  /*
2081  * (Re-)Initialize our idea of the latest page number for members.
2082  */
2083  pageno = MXOffsetToMemberPage(offset);
2084  MultiXactMemberCtl->shared->latest_page_number = pageno;
2085 
2086  /*
2087  * Zero out the remainder of the current members page. See notes in
2088  * TrimCLOG() for motivation.
2089  */
2090  flagsoff = MXOffsetToFlagsOffset(offset);
2091  if (flagsoff != 0)
2092  {
2093  int slotno;
2094  TransactionId *xidptr;
2095  int memberoff;
2096 
2097  memberoff = MXOffsetToMemberOffset(offset);
2098  slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
2099  xidptr = (TransactionId *)
2100  (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
2101 
2102  MemSet(xidptr, 0, BLCKSZ - memberoff);
2103 
2104  /*
2105  * Note: we don't need to zero out the flag bits in the remaining
2106  * members of the current group, because they are always reset before
2107  * writing.
2108  */
2109 
2110  MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2111  }
2112 
2113  LWLockRelease(MultiXactMemberSLRULock);
2114 
2115  /* signal that we're officially up */
2116  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2118  LWLockRelease(MultiXactGenLock);
2119 
2120  /* Now compute how far away the next members wraparound is. */
2121  SetMultiXactIdLimit(oldestMXact, oldestMXactDB, true);
2122 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:587
uint32 TransactionId
Definition: c.h:575
MultiXactOffset nextOffset
Definition: multixact.c:206
#define MemSet(start, val, len)
Definition: c.h:1004
#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:1811
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:2208
TransactionId MultiXactId
Definition: c.h:585
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1207
#define MultiXactMemberCtl
Definition: multixact.c:191

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  newOldestMulti,
Oid  newOldestMultiDB 
)

Definition at line 2939 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().

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

◆ WriteMTruncateXlogRec()

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

Definition at line 3198 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().

3201 {
3202  XLogRecPtr recptr;
3203  xl_multixact_truncate xlrec;
3204 
3205  xlrec.oldestMultiDB = oldestMultiDB;
3206 
3207  xlrec.startTruncOff = startTruncOff;
3208  xlrec.endTruncOff = endTruncOff;
3209 
3210  xlrec.startTruncMemb = startTruncMemb;
3211  xlrec.endTruncMemb = endTruncMemb;
3212 
3213  XLogBeginInsert();
3214  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3215  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3216  XLogFlush(recptr);
3217 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2847
#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 3184 of file multixact.c.

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

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

3185 {
3186  XLogBeginInsert();
3187  XLogRegisterData((char *) (&pageno), sizeof(int));
3188  (void) XLogInsert(RM_MULTIXACT_ID, info);
3189 }
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 1942 of file multixact.c.

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

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

1943 {
1944  int slotno;
1945 
1946  slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
1947 
1948  if (writeXlog)
1950 
1951  return slotno;
1952 }
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:73
static void WriteMZeroPageXlogRec(int pageno, uint8 info)
Definition: multixact.c:3184
#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 1926 of file multixact.c.

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

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

1927 {
1928  int slotno;
1929 
1930  slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
1931 
1932  if (writeXlog)
1934 
1935  return slotno;
1936 }
static void WriteMZeroPageXlogRec(int pageno, uint8 info)
Definition: multixact.c:3184
#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